MCtools/latextools (April 11, 2009)   Open Execute Close  

>     restart;

>   

>   

>    ######MCtools

>    MCtools:= module()
local ver,MYMAGIC_,chkp,chkf;
global BOXLENGTH_,ERROR_,MAGIC_,MCTOOLS_,PNUM_,WBOX_,RNGCHK_,CHK_,STANDARDS_,Standardize,PValList;
export MCdefaults,addlink, addimg,addsectionhint, ah_, addvlink,archiveit, ARRW, av_, Axes,
       brak,  CARR, colors, DL, DV, fill, generator, GP, GP2, GP3,
       hashang,  Header, htmltable, Line, Autoline,lineit,
       maketable, mctools, mcpiecewise,PCWSE, mcprint,  MM,
       PA, PARAMS, PC, PP,PT, RANDANS, roundto,roundit,
       show_answers, symbolize, tableit, tagit, vspace, hspace, zipit,filter7,       changepic,AKhint,stagit,ltagit,format,makeheader,savepic,vbutbox,tbuttons,`&=`,`&==`,assignvals,getparams,
asciimat,rascim,ra,la,big,text,tex,addpic,putpic,rel,rla,ac_,an_,aef_,af_,ae_,as_,ai_,aw_,rlprint,ltlt,
rap,abc_,arq_,acew_,ragit,ar_,aq_,paramvals,tr,cnv;

options package;

ver := "4/11/2009":

#### RESET these variables
MYMAGIC_:="cda80d34-8ed1-4f74-952b-0c053bf263d6";   ##NOTE: Change this value to your guid before archiving.  


### ragit


ragit:= proc()
   global LATEX_:
   local ARGS,strg,a,b,storit:
   if nargs>0 and args[1]=Help then
mcprint("Use ragit for automated formating choices, in either latex or html.  Strings, expressions, and answer formats ac_, af_, ae_, ai_, an_, aw_, acew_, as_, and arq_ are used to form the questions.  Use brak() to give line breaks. By expressions we mean ordinary algebraic and functional expression together with Diff, Int, Pdiff, Lim, Mat, Det, Tab,ColVec, RowVec, Pnt, PCwise, Syseqn, Binomial, Product, Sum."); return NULL fi;
   storit:=proc(a)
    if strg="" then ARGS:=ARGS,a:
              else strg:=[strg]: ARGS:=ARGS,strg,a; strg:="":
    fi;
   NULL:
   end;
   ARGS:=NULL;strg:="":
   #print(args);
    for a in [args] do
      if type(a,string) then  
         if StringTools[Search]("lt_",a)=0 then
             strg:=cat(strg,a):
         else  storit(a);
         fi
      elif member(whattype(a),{float,symbol,algebraic,integer,fraction,numeric,function,`+`,`*`,`^`}) then
         if not member(op(0,a),{PLOT,_AC,_AB,_AN,_AS,_AX,_AF,AW_,_AI,_AL,_AR,_AT,_AE,_Ar,_ALlabels,_ABlabels,_ATcross,AKhint,_Aq}) then
           strg:=cat(strg,op([rlprint(a)])) else  storit(a) fi;
      elif type(a,`=`)  then
         if  member(lhs(a),{txtboxsize,precision,matsize,pretext,standards,hidden}) then
            storit(a) else strg:=cat(strg,rlprint(a)) fi
      elif whattype(a)=exprseq then
           for b in [a] do
           ARGS:=ARGS,b od:
       elif type(a,list) and nops(a)=1 and type(a[1],string) then
                if StringTools[Search](["_Brk_","\\Par"],op(a))<>0 then strg:=cat(strg,"\n",op(a))
                   else strg:=cat(strg,op(a))
                fi;
       else  ARGS:=ARGS,a fi;
      
      od;
   ltagit(ARGS,[strg]);
   NULL:
end:

cnv := table([]);
cnv[leq] := ["\\leq ", " <= "];
cnv[lt] := [" < ", " < "];
cnv[geq] := ["\\geq ", " >= "];
cnv[gt] := [" > ", " > "];
cnv[neq] := ["\\neq ", " <> "];
cnv[xx]:=[" \\times "," xx "];
cnv[`-:`]:=[" \\div "," -: "];
cnv[cup]:=["\\cup "," uu "]:
cnv[cap]:=["\\cap "," nn "]:
cnv[sub]:=["\\subset "," sub "]:
cnv[elt]:=["\\in "," in "]:
cnv[`-=`]:=["\\equiv "," -= "]:
cnv[pm]:=["\\pm ","+-"]:
cnv[int]:=["\\displaystyle\\int","int"]:
cnv[oint]:=["\\displaystyle\\oint"," oint"]:
cnv[del]:=["\\del "," del "]:
cnv[grad]:=["\\nabla ","grad"]:
cnv[infty]:=["\\infty ","infty"]:
cnv[empty]:=["\\emptyset ","0/"]:
cnv[aleph]:=["\\aleph"," aleph "]:
cnv[angle]:=["\\angle"," /_ "]:
cnv[cdots]:=["\\cdots "," cdots "]:
cnv[cdot]:=["\\cdot "," * "]:
cnv[tri]:=["\\triangle "," triangle "]:
cnv[perp]:=["\\perp "," _|_ "]:


tr:=proc ()
local  a,t,syns;
syns:=map(op,[indices(cnv)]):
if nargs=0 or StringTools[Search]("Help",convert(args[1],string))<>0 then mcprint(
"cat(tr(a1,a2,...) returns a  string formatted either with $ (if LATEX_=yes) or `.  The ai's can be regular expressions, strings, or the terms
",StringTools[Join](map(convert,syns,string),","),".
Note: The division  and  equivalent symbols `-:` and `-=` must be backquoted.");
return NULL fi:  

t:=proc(a)  
if member(a,syns)
   then  if LATEX_ = yes
   then cnv[a][1]
   else cnv[a][2]
   fi
else rascim(a)
fi
end:
rla(op(map(t,[args])))
end:

acew_ := proc(Lst)
  local i,j,k,defaults,opts,help,nc,c,tabopts,cellopts,co,lst,d,ret,n,lab,bc,br,ec,er,tlst,ttlst,l,List;
    if member(args[1],{Help,Help=yes,"Help"}) then mcprint(
"acew_(lst::listlist) constructs an array of strings, expressions, and answer formats ac_,an_,af_,ae_,ai_,aw_   
 Options:
 Help=no acew_(Help) will retrieve this help
 Numcols=1  increase as needed
 Tableopts=\"\"  replace with an appropriate format string
 Cellopts=\"\"   replace with a format such as \"color=\\\"yellow\\\"\" for all cells or a list of");
 RETURN(NULL) fi:

 defaults:=Numcols=1,Tableopts="",Cellopts="";
 opts := subs([ op(select(type,[args],`=`)),defaults],[Numcols,Tableopts,Cellopts]);  
 nc :=opts[1]:
  tabopts:=opts[2]:
  cellopts:=opts[3]:
  lst:=NULL:

if not LATEX_=yes then
if type(Lst,listlist) then

nc:=nops(Lst[1]):
  for i from 1 to nops(Lst) do
   for j from 1 to nops(Lst[i]) do
lst:=lst,Lst[i][j] od od;
 lst := [lst]
else lst:=Lst fi:
n := nops(lst);
d := iquo(n,nc);
if irem(n,nc)<>0 then d:=d+1; lst:=[op(lst),seq([""],i=1..(n-(d-1)*nc))] fi:

if type(cellopts,listlist) then
  for i from 1 to nops(cellopts) do
   for j from 1 to nops(cellopts[i]) do
lst:=lst,cellopts[i][j] od od;
 cellopts := [cellopts]
elif type(cellopts,string) then cellopts:=[seq(cellopts,i=1..d*nc)]
elif type(cellopts,list) and nops(cellops)=n then lst:=cellopts
else error "check Cellopts"  
fi:
  bc:="lt_td ": ec:="lt_/td gt_": br:= "lt_tr gt_": er:="lt_/tr gt_":
  k:=cat("lt_table ",tabopts," gt_");

for i from 0 to d-1 do
   k:=k,br;
 for j from 1 to nc do
     if j+i*nc <= n then
         if member(op(0,lst[i*nc+j]),{_AC,_AN,_AW,_AF,_AE,_AI}) then
           lab:=cat(bc," gt_"),lst[i*nc+j],ec
         else  lab:=cat(bc,cellopts[i*nc+j]," gt_"),rlprint(lst[i*nc+j]),ec
         fi  
     else lab:=cat(bc," ",ec)
     fi:       
     k:= k,lab;
      od:
     k:= k,er;
 od;
 k:= k,"lt_/table gt_";#unlisted
 ret:=  k;

else

List:=ListTools[FlattenOnce](Lst);

tlst:=NULL:
lst:=NULL:
for l in List do

if op(0,l)=_AX then
tlst:=tlst,l;
else lst:=lst,l;
fi
od:
lst:=[lst]:
n:=nops(lst):   
d := iquo(n,nc);
if irem(n,nc)<>0 then d:=d+1; lst:=[op(lst),seq([""],i=1..(n-(d-1)*nc))]  fi:

k:=cat("\\begin{tabular}{",seq("l",i=1..nc),"}\n");
for i from 0 to d-1 do
 for j from 1 to nc do
     k:=cat(k,rlprint(lst[i*nc+j]));
   
     if j < nc then
     k := cat(k," & ") else k := cat(k,"\\\\\n",seq(" &",i=1..nc-1),"\\\\\n")
     fi;
 od:
 od;
  k := cat(k,"\\end{tabular}\n");
 ret:= k,tlst:  
fi;
ret  
   end:
##end acew_

###arq_

arq_ := proc(Lst)
  local af,i,j,k,p,id,defaults,opts,help,m,mtmp,nc,c,tabopts,cellopts,co,button,q,lst,labels,labels1,labels2h,labels2l,d,dirs,abox,ret,n,lab,bc,br,ec,er,tlst;
    if member(args[1],{Help,Help=yes,"Help"}) then mcprint(
"arq_(lst::listlist) constructs an array of radio buttons (default) or checkboxes  
 alternatives with the same identifier (Id below).
 The first alternative is assumed the correct one, unless modified appropriately
 with the Rightone= option.
 Options:
 Help=no
 Button=\"radio\"  change to Button=\"checkbox\" for an array of checkbox alternatives
              Note: Use ar_ for radiobuttons and aq_ for checkboxes.
 Rightone=1   For Button=\"radio\" change to the correct alternative as needed.
              For Button=\"checkbox\" change to a list of correct alternatives
 Numcols=1   Change to the number of columns you want.
 Shuffle=no   Insert a permutation of the number of alternatives (eg, Shuffle=[3,1,2]) to shuffle the positions
              For problem maintainance purposes, in a problem generator, if is recommended that you
              generate the permutation of the alternatives using getparams
              or change no to yes to get a random permutation.
 Id = -rand(1..10000)()   If you want a particular identifier, use a positive
  integer if you want WHS to shuffle it, otherwise use a negative integer
 Labels=\"\"  Replace by Labels=1 to get [\"A) \",\"B) \", etc] or Labels=2 to get red letter labels in html.
              or Labels=[any list of strings]
 Tableopts=\"\"  replace with
an appropriate format string
 Cellopts=\"\"   replace with a format string for all cells or a list of
 pairs [n,string], where n is the cell number to be formatted with string.");
 RETURN(NULL) fi:

abox:=cat(latextools[ansbox](Height=.1,Width=.1,Fill="",Placement="c"),"\\ "):
labels1:=[seq(cat(convert([i+65],'bytes'),") "),i=0..25)]:
labels2h:=[seq(cat("lt_font color=\"red\" gt_lt_b gt_",convert([i+65],'bytes'),") lt_/b gt_ lt_/font gt_ "),i=0..25)]:
labels2l:=[seq(cat("\\ \\textbf{",convert([i+65],'bytes'),")}"),i=0..25)]:
  defaults:=Shuffle=no,Id=-rand(1..10000)(),Rightone=1,Numcols=1,
Tableopts="",Cellopts="",Button="radio",Labels="",Directions="";
 opts := subs([ op(select(type,[args],`=`)),defaults],[Shuffle,Id,Rightone,Numcols,Tableopts,Cellopts,Button,Labels,Directions]);
  p:=opts[1]:
  id :=opts[2]:
  m:=opts[3]:
  nc :=opts[4]:
  tabopts:=opts[5]:
  cellopts:=opts[6]:
  button:=convert(opts[7],string): if member(button,{"radio","R"}) then button:="R" elif
                 member(button,{"checkbox","Q"}) then button:="Q" else error "Button options are radio or checkbox" fi:
  labels:=opts[8]:
  dirs:=opts[9]:
  
 if member(whattype(Lst),{array,Matrix})  then
     tlst:=convert(Lst,listlist);
     m := NULL:
     nc:=nops(tlst[1]);
     lst:=NULL:
     for i from 1 to nops(tlst) do for j from 1 to nc do
      if type(Lst[i,j],list) then lst:=lst,Lst[i,j]; m:=m,nc*(i-1)+j
      else lst:=lst,[Lst[i,j]];
      fi; od od;
      lst:=[lst];
      if button="R" and (nops([m])>1 or nops([m])=0 )
         then error "radio buttons must have exactly one correct"
      fi;
      if  button="Q" then m:=[m];  
      fi:   
 else  
    if m<>0 then lst := NULL:
       for i from 1 to nops(Lst) do
         if type(Lst[i],list) then lst:=lst,Lst[i];
         else lst:=lst,[Lst[i]] fi:
       od:
       lst:=[lst]:  
    else
      lst:=NULL:  m := NULL:
      for i from 1 to nops(Lst) do
        if not type(Lst[i],list) or not member(Lst[i][1],{0,1}) then
          ERROR("When Rightone=0, you must mark the correct alternatives with 1 and incorrect ones with 0.")
        fi;
        if Lst[i][1]=1 then m := m,i
        fi;
        lst := lst,[seq(Lst[i][j],j=2..nops(Lst[i]))];
      od;
      lst:=[lst];
      if button="Q" then m := [m];
      fi;   
   fi;
fi;

  if type(cellopts,string) then cellopts:=[seq(cellopts ,i=1..nops(lst))]
  elif type(cellopts,list) then co:=NULL;j:=1;
  for i from 1 to nops(lst) do
 
  if j <= nops(cellopts) and cellopts[j][1]=i then co:=co,cellopts[j][2];
  j:=j+1 else co:=co,"" fi od;
  cellopts:=[co];
  else ERROR("Check arq_(Help) for syntax of Cellopts");
  fi;

if p=no then p:=[seq(i,i=1..nops(lst))]
 elif p=yes then p:=combinat[randperm]([seq(i,i=1..nops(lst))])
else if not type(p,list) or nops(p)<>nops(lst) or max(op(p))<>nops(lst) then
   error "Shuffle must be a permutation of 1 thru no. of alternatives." fi fi;

 
if button="R" then mtmp:=-1:
  for i from 1 to nops(p) do
  if p[i]=m then mtmp:=i;  fi od:
  if mtmp>-1 then m := mtmp else ERROR("Need a Rightone=") fi

  elif button="Q" then q := "";
  for i from 1 to nops(p) do
  if member(p[i],{op(m)}) then q:=cat(q,";",convert(i,string))
       else   q := cat(q,";")  fi;
  od:
   m := q;
fi;

n:=nops(lst);
if nc>n then nc:=n: fi:
d:=iquo(n,nc);

if irem(n,nc)<>0 then d:=d+1: fi;

if type(labels,string) then labels:=[seq(labels,i=1..n),seq("",j=1..n-(d-1)*nc)]
                   elif type(labels,list) then labels:=[op(labels),seq("",j=1..n-nops(labels))]
                   elif labels=1 then labels:=[seq(labels1[i],i=1..n),seq("",j=1..n-(d-1)*nc)]
                   elif labels=2 then labels:=[seq(labels2h[i],i=1..n),seq("",j=1..n-(d-1)*nc)]
                   elif labels=3 then labels:=[seq(labels2l[i],i=1..n),seq("",j=1..n-(d-1)*nc)] fi;
  lst:=[op(lst),seq([""],i=1..(n-(d-1)*nc))];

 
if not LATEX_=yes then
  bc:="lt_td gt_": ec:="lt_/td gt_": br:= "lt_tr gt_": er:="lt_/tr gt_":
  af := cat("A",button,"_[",convert(id,string),";1]\n");
  k:=cat("lt_table ",tabopts," gt_");#unlisted
 
for i from 0 to d-1 do
   k:=k,br;
 for j from 1 to nc do
     if j+i*nc < n then lab:=bc,af,labels[i*nc+j],rlprint(op(lst[p[i*nc+j]])),ec
     elif j+i*nc=n then if button="R" then lab:=bc,_Ar([id,m]),labels[n],rlprint(op(lst[p[n]])),ec
                        else lab:=bc,_Aq([id,m]),labels[n],rlprint(op(lst[p[n]])),ec
                        fi;
          
     else lab:=cat(bc," ",ec) fi:
       
     k:= k,lab;
      od:
     k:= k,er;
od;
 k:= k,"lt_/table gt_";#unlisted
 ret:=  k;
else
if button="R" then k:=dirs else k:=dirs fi;
k:=cat(k,"\\begin{tabular}[t]{",seq("l",i=1..nc),"}\n");
for i from 0 to d-1 do
 for j from 1 to nc do  
     if j+i*nc <= n then lab:=abox,labels[i*nc+j],rlprint(op(lst[p[i*nc+j]])) else lab:="" fi:
     k:= cat(k,lab);
     if j < nc then k := cat(k," & ") else k := cat(k,"\\\\\n",seq(" &",i=1..nc-1),"\\\\\n") fi;
 od:
   
 od;
  k := cat(k,"\\end{tabular}\n");
 ret:= [k],_AX(m):  
fi;
ret  
   end:
##end arq_

abc_:=proc()
arq_(args);
end:

>    ar_:=proc()
   local n:
   if LATEX_=yes then
   arq_(args,Button="R")
   else
   arq_(args,Button="R")
   fi;
 end:
  
  

>    aq_:=proc()
   if LATEX_=yes then
   arq_(args,Button="Q")
   else
   arq_(args,Button="Q")
   fi;
 end:

>   

rlprint:=proc ()
local lst, ans, l;
if nargs = 0 or args[1]="Help" then
mcprint("rlprint(...,argi,...) returns a catted string of the argi's
where if argi an expression, it is converted to $-enclosed latex (by la if LATEX_=yes) or `-enclosed ascmimath
(by ra is LATEX_ is not yes).   
If  args[1]=\"$\" or args[1]=\"$$\" then the catted string is started and ended with the same
and expressions are not $-signed, otherwise expressions are $-signed. An analogous string is returned if args[1]=\"`\" "); return NULL fi;
lst := [args]; ans := "";
if LATEX_=yes then
  if lst[1] = "$" or lst[1] = "$$" then
     for l in lst while true do
       if type(l,string) then ans := cat(ans,l)
       else ans := cat(ans,la(l))
       fi
     od;
     if lst[1] = "$" and lst[-1] <> "$" then ans := cat(ans,"$") fi;
     if lst[1] = "$$" and lst[-1] <> "$$" then ans := cat(ans,"$$") fi
  else for l in lst while true do
     if type(l,string) then ans := cat(ans,l);
     else ans := cat(ans,la(l))
     fi od:
  fi;
else
  if  lst[1] = "`"  then
    for l in lst while true do
      if type(l,string) then ans := cat(ans,l)
      else ans := cat(ans,ra(l))
      fi
    od;
    if lst[1] = "`" and lst[-1] <> "`" then ans := cat(ans,"`") fi;  
  else for l in lst while true do
    if type(l,string) then ans := cat(ans,l);  
    else ans := cat(ans,ra(l))
    fi od  
  fi;
fi;
ans
end:

rap :=proc()
   rlprint(args); end:

as_ :=proc(l)
   local cands,ans,i,p,r,abox,defaults,opts,shuf,right1;
   if StringTools[Search]("Help",convert(l,string))<>0 then mcprint("as_(l)  returns a list from which to circle
 the correct answer (listed first or enclosed in square brackets)if LATEX_=yes, else it returns an AS format for tagit, taking the same arguments (randomize and rightanswers)  the tagit format does.
Options:
Shuffle=no, or =yes or =[3,2,1] to reverse the order of 3 alternatives
Rightone=1  Change if the correct answer is not the first answer."); return NULL fi:

defaults:=Shuffle=no,Rightone=1,randomize="",rightanswers="";
opts:=subs([op(select(type,[args],`=`)),defaults],[Shuffle,Rightone,randomize,rightanswers]);
shuf:=opts[1]:
if opts[3]<>"" then shuf:=opts[3]: fi:
right1:=opts[2]:
if opts[4]<>"" then right1:=opts[4]: fi;

      
 if shuf=no then p:=[seq(i,i=1..nops(l))]
 elif shuf=yes then p:=combinat[randperm]([seq(i,i=1..nops(l))])
 elif type(shuf,list) and nops(shuf)=nops(l) and max(op(shuf))=nops(l) then p:=shuf
else
   error "Shuffle must be a permutation of 1 thru no. of alternatives."  fi;

ans:=right1;
 
     cands:=NULL;
     for i from 1 to nops(l) do
     r:=l[i]:
     if type(r,list) then r:=op(r): ans:=i fi;
     cands:=cands,r;
     od:
     if LATEX_=yes then
     
     arq_(args,Directions="",Shuffle=p,Rightone=ans,Numcols=nops([cands]))
     else _AS([seq(cands[p[i]],i=1..nops(l))],randomize=shuf,rightanswers=cands[ans])  
     fi
  end:
  

>    ac_ :=proc()
   local opts,targs,abox,i,a,ar;
   if nargs=0 or StringTools[Search]("Help",convert(args[1],string))<>0 then mcprint("ac_(a)  returns answer box if LATEX_=yes else it returns an ac format for tagit, taking the same arguments that the tagit format.
Options: ansbox=[Height=.4,Width=1,Fill=\"\",Placement=\"c\"]  change to a list of arguments to ansbox (see ansbox(Help=yes) for options)"); return NULL fi:
  opts:=[]: targs:=NULL:
 a:=args[1]:  
 if nargs>1 then for i from 2 to nargs do
    ar:=args[i]:
    if type(ar,`=`) then if member(lhs(ar),{txtboxsize,precision}) then targs:=targs,ar
                         elif lhs(ar)=ansbox then opts:=rhs(ar)
                         else error "options allowed are ansbox,txtboxsize,precision"
                         fi;
    else error "all but the first argument must be an option."
    fi;
od
fi;
       if LATEX_=yes then [latextools[ansbox](op(opts))],_AX(la(a))
    else _AC(a,targs) fi
 end:

an_:=proc()
  if nargs>0 and StringTools[Search]("Help",convert(args[1],string))<>0 then
mcprint("acts like AN in html and ac in latex."): return NULL: fi;
  if LATEX_=yes then ac_(args) else  _AN(args) fi end:

>   
aef_ :=proc()
   local opts,targs,abox,i,a,ar,var,fun,tbs;
   if nargs>0 and StringTools[Search]("Help",convert(args[1],string))<>0 then
mcprint("aef_(f)  returns an answer box if LATEX_=yes else it returns an ae or af format for tagit (depending on the number of variables), taking as options txtboxsize (the length of the entry box for the answer in mathclass), precision (the absolute error allowed in the evaluation of the correct function and the student answer), and checkints (a list giving the intervals (one for each variable) that the function is evaluated in).
Options:
   txtboxsize=15
   precision= the default
   ansbox=[Height=.4,Width=1,Fill=\"\",Placement=\"c\"]  change to a list of arguments to ansbox (see ansbox(Help=yes) for options)");
 return NULL fi:
  opts:=[txtboxsize=15]: targs:=NULL:tbs:=15:
 a:=args[1]:
 var:="";
 if nargs>1 then for i from 2 to nargs do
    ar:=args[i]:
    if type(ar,`=`) then
           if member(lhs(ar),{txtboxsize,precision}) then
              targs:=targs,ar;
              if lhs(ar)=txtboxsize then tbs:=convert(rhs(ar),string)
              fi:                                          
           elif member(lhs(ar),{chkints,funstuff}) then
             var:=convert(indets(a,symbol),list):
             if nops(var)=0 then var:={x}
             fi;
             ar:=rhs(ar);
             if type(ar,string) then
                fun:=ar;
             elif type(ar,list) then
                fun:="":
                if nops(var)>1 then fun :=cat(fun,convert(nops(var),string),";",
                         StringTools[Join](map(convert,var,string),";"));
                if irem(nops(ar),2)=1 then  
                   fun:=cat(fun,";",convert(ar[1],string),";");
                   ar:=ar[2..nops(ar)];
                else fun:=cat(fun,";",convert(6^min(2,nops(var)),string),";")
                fi;
                if nops(ar)>2*nops(var) then
                   ar:=[seq(ar[j],j=1..2*nops(var))]
                elif nops(ar)<2*nops(var) then
                   ar:=[op(ar),seq(op([.1,1]),j=1..(nops(var)-nops(ar)/2))]
                fi;
                fun:=cat(fun,StringTools[Join](map(convert,ar,string),";"));
                else fun:=var[1];
                if irem(nops(ar),2)=1 then fun:=[fun,ar[1],ar[2],ar[3]]
                 else fun:= [fun,6,ar[1],ar[2]]  fi;
               fi;
             else error "check chkints format"
             fi;  
           elif lhs(ar)=ansbox then opts:=rhs(ar)
           else error "options allowed are ansbox,txtboxsize,precision,funstuff"
           fi;
    else error "all but the first argument must be an option."
    fi;
od
fi;
    if LATEX_=yes then [latextools[ansbox](op(opts))],_AX(la(a))
    elif nops(indets(a,symbol))<2 then
          if var="" then   _AF(a,targs) else _AF(a,targs,funstuff=fun) fi;
    else  if var="" then _AE(a,targs) else _AE(a,targs,funstuff=fun) fi
    fi;
 end:

ae_:=proc()
   aef_(args) end:

af_:=proc()
   aef_(args) end:

ai_ :=proc(a)
   local opts,targs,abox,i,ar,tbs,var,ans;
   if StringTools[Search]("Help",convert(a,string))<>0 then mcprint("ai_(f)  returns answer box if LATEX_=yes else it returns an ai format for tagit, taking as options txtboxsize (the length of the entry box for the answer in mathclass), precision (the absolute error allowed in the evaluation of the correct function and the student answer), and chintervals (a list giving the intervals  that the function is evaluated in).
Options: txtboxsize=15,
         precision= default value
         chkinterval= default values
         ansbox=[Height=.4,Width=1,Fill=\"\",Placement=\"c\"]  
              change to a list of arguments to ansbox (see ansbox(Help=yes) for options)");
return NULL fi:
  abox:=[]: tbs:=15: targs:=NULL:
  var:=indets(a,symbol):
 if nops(var)=0 then var:={x} fi;
 if nops(var)>1 then
       error "the answer cannot have more than 1 variable"
 fi;  
 if nargs>1 then for i from 2 to nargs do
    ar:=args[i]:
    if type(ar,`=`) then if member(lhs(ar),{txtboxsize,precision}) then
                             if lhs(ar)=txtboxsize then tbs:=rhs(ar) fi:
                             if lhs(ar)=precision then targs:=targs,ar; fi;
                         elif member(lhs(ar),{chkinterval,funstuff}) then
                               
                         targs:=targs,funstuff=[op(var),6,op(rhs(ar))];
                         elif lhs(ar)=ansbox then abox:=rhs(ar)
                         else error "options allowed are ansbox,txtboxsize,precision,chkinterval"
                         fi;
    else error "all but the first argument must be an option."
    fi;
od
fi;
    if LATEX_=yes then [latextools[ansbox](op(abox))],_AX(la(a))
    else _AI(a,targs,txtboxsize=tbs) fi
 end:

aw_ :=proc(a)
   local opts,targs,abox,i,ar,ans,tbs;
   if StringTools[Search]("Help",convert(a,string))<>0 then mcprint("aw_(w)  returns an answer box if LATEX_=yes else it returns an aw format for tagit, taking the same arguments that the tagit format.
Options: ansbox=[Height=.4,Width=1,Fill=\"\",Placement=\"c\"]  change to a list of arguments to ansbox (see ansbox(Help=yes) for options)
         txtboxsize=20"); return NULL fi:
  opts:=[]: targs:=NULL: tbs:=20:  
 if nargs>1 then for i from 2 to nargs do
    ar:=args[i]:
    if type(ar,`=`) then if member(lhs(ar),{txtboxsize}) then tbs:=rhs(ar)
                         elif lhs(ar)=ansbox then opts:=rhs(ar)
                         else error "options allowed are ansbox and txtboxsize"
                         fi;
    else error "all but the first argument must be an option."
    fi;
od
fi;
       if LATEX_=yes then
         if type(a,list) then ans := cat(StringTools[Join](map(convert,a,string),", "))
         else ans:=StringTools[SubstituteAll](a,"#",", ")
         fi;
        [latextools[ansbox](op(opts))],_AX(lxprint(ans))
      else
         if type(a,list) then ans := cat(StringTools[Join](map(convert,a,string),"#"))
         else ans:=a
         fi;
       _AC(ans,txtboxsize=tbs)
      fi
 end:


####addpic2/17/09
addpic := proc()
local defaults,opts,help,h,w,writ,latx,fmt,nam,hfill,bill,center,optins,pltopts,cnvrt,pic,name;
defaults:=Help=no,Width=160,Height=120,Write=yes,Latex=no,Format=gif,Center=no,Hfill=no,Plotoptions="",Convertjpg=no;
opts:=subs([op(select(type,[args],`=`)),defaults],[Help,Width,Height,Write,Latex,Format,Center,Hfill,Plotoptions,Convertjpg]);
help:=opts[1]:
w:=convert(opts[2],string):
h:=convert(opts[3],string):
writ:=opts[4]:
latx:=opts[5]:
fmt:=opts[6]:
center:=opts[7]:
hfill:=opts[8]:
pltopts:=opts[9]:
cnvrt:=opts[10]:

if StringTools[Search]("Help",convert(args[1],string))<>0 then help:=yes fi:

if help=yes then
mcprint("addpic(pic,name)  saves a plotstucture pic to name.gif in the
current directory and writes an img src into the source worksheet, unless
LATEX_=yes or Latex=yes. In that case, pic is saved to name.eps and an
includegraphics is written into the source worksheet.
addpic(name) writes an img src or includegraphics into the source worksheet,
 and checks to see if name.Format exists in the current directory.
Options:
Latex = no Change to yes for a latex file.
Format=gif Change to eps,jpg,bmp,pcx as desired.  If Latex or LATEX_ = yes,
 jpeg and jpg is automatically converted to eps by jpeg2ps by Thomas Mertz, if you have it.
 and have set Convertjpg=yes
Height=120 units are points
Width=160  units are points
Write=yes  Change to no to reuse a previously stored file
Hfill=no Change to before, after, both to put an hfill in those locations
Center=no Change to yes to center the picture
Plotoptions=\"\" Change this only if you must. This replaces the string used by plotsetup which is constructed
by addpic."); RETURN(NULL) fi;

if StringTools[Search]("Files\\Maple",currentdir())<>0 then
      error "Please use currentdir() to set the homework directory before writing with addpic." fi;

if op(0,args[1])=PLOT then pic:=args[1]:name:=convert(args[2],string); writ:=yes:
elif type(args[1],string) then name:=args[1]: writ:=no:
else error "First argument should be a plot structure or a string."  fi:
 
nam:=cat(convert(name,string),".",convert(fmt,string)):

if not writ=yes and not FileTools[Exists](nam) then error cat(nam," does not exist in ",currentdir()) fi;
if writ=yes then
  if LATEX_=yes or latx=yes and fmt=gif then fmt:=eps; nam:=cat(convert(name,string),".eps"): latx:=yes fi:
  if pltopts="" then
    if member(fmt,{ps,eps}) then
       pltopts:=cat("width=",w,"pt,height=",h,"pt,shrinkby=.0,noborder,portrait,color=cmyk")
    else       
       pltopts:=cat("width=",w,"pt,height=",h,"pt")
    fi;
  fi;
  plotsetup(fmt,plotoutput=nam,plotoptions=convert(pltopts,symbol)):
  print(pic):
  plotsetup(default):  
else nam:=nam
fi:

optins:=cat("width=",w,"pt,height=",h,"pt");

if LATEX_=yes or latx = yes then
bill := "\\includegraphics[";
    if member(fmt,{jpg,jpeg}) then
       if not FileTools[Exists](cat(name,".",convert(fmt,string))) then
          error   cat(nam," does not exist in ",currentdir())
       fi;       
       if not FileTools[Exists](cat(name,".eps")) then  
          if system(cat("jpeg2ps -o ",name,".eps  ",name,".",convert(fmt,string)))<>0 then
           error "the jpeg or jpg format must be converted to eps.  Get jpeg2ps by Thomas Mertz and put it in your path."
          fi:           
       fi:
       nam:=cat(name,".eps"):
    elif member(fmt,{eps,ps}) then name:=cat(name,".",convert(fmt,string))
    elif member(fmt,{bmp,pcx}) then
       optins:=cat("bb 0 0 ",w," ",h," ",optins);
       nam:=cat(name,".",convert(fmt,string));
    else error cat(" The format ",convert(fmt,string)," is not usuable in latex.")
    fi;
 if hfill<>no then
    if hfill=before then bill := cat("\\hfill",bill,optins,"]{",nam,"}")
    elif hfill=after then bill=cat(bill,optins,"]{",nam,"}\\hfill")
    elif hfill=both then bill=cat("\\hfill",bill,optins,"}{",nam,"}\\hfill")
    else bill=cat(hfill,bill,optins,"]{",nam,"}")
    fi;
 else bill:=cat(bill,optins,"]{",nam,"}")
 fi;
 if center=yes then bill := cat("\\begin{center}",bill,"\\end{center}")  fi;  
else bill:=  cat("lt_img src=\"",nam,"\" alt=\"MaplePlot\" /gt_");
if center=yes then bill:=cat("lt_center gt_ ",bill," lt_/center gt_") fi;
fi;
bill;  
end:
###end addpic

###putpic
putpic:=proc()
  error "Please use addpic instead of putpic.   See addpic(Help) for usage." end;  



###rascim  1/31/09

rascim:= proc( )
local defaults,opts,expr,aexp,typ,li,sexp,alst,left,right,ck1,latex,surds,parens,ck2,Args,bill,sam,mat,i,j,esymb,fsymb,r,l,s;
#if nargs>1 then Args:=[seq(args[i],i=2..nargs)] else Args:=[NULL] fi:
if member(args[1],{Help=yes,Help,help}) then mcprint("rascim(expr) converts an expression into an asciimath
expresion suitable for mathclass homework. Use ra(expr sequence) to convert a sequence of expressions and strings into an asciimath expression surrounded by backquotes `.
It also can return a latex expression. Use la(expr sequence) to convert a sequence of expressions and strings into a latex expression surrounded by dollar signs $.
Note: In a ragit line, rascim is automatically called as needed.
Special functions:  Diff, Int, Pdiff, Syseqn, Mat, Det, Tab, ColVec, RowVec, Pnt, Pcwise, Binomial, Sum, Product.      
options:
Latex=no  change to yes to get latex
Surds=yes  This does surds for powers of roots rather than fractional exponents
           change this to no if you want the usual crappy fractional powers.");
             return NULL ; fi;
expr:=args[1];
defaults:=Latex=yes,Surds=yes,Parentheses=no;
opts:=  selectremove(type,[args],`=`);
 opts:=subs([op(opts[1]),defaults],[Latex,Surds,Parentheses]):
 latex:=opts[1]:  if LATEX_=no then latex:=no else latex:=yes fi;  # added 2/15/09
 surds:=opts[2]:
 parens:=opts[3]:
 Args:=[Latex=latex,Surds=surds,Parentheses=parens]:
ck1:=proc(expr,lst)
   local l;
   for l in lst do if type(expr,l) then return true fi od;
   if member(type(op(0,expr)),lst) then return true fi;
   if member(type(op(1,expr)),lst) then return true fi;
   if member(whattype(expr),lst) then return true fi;
   false end:
ck2:=proc(expr)
     #print(type(expr,`^`),op(0,expr),op(expr),op(2,expr),type(op(2,expr)));
     if type(expr,`^`) and  type(evalf(op(2,expr)),float) and evalb(evalf(op(2,expr))<0) then true else false fi end:
#debug(ck2);  
      
use StringTools in

#handle lists
if type(expr,set) then
   if nops(expr)=0 then aexp:="" else
      aexp:=cat(seq(op([rascim(expr[i],op(Args)),","]),i=1..nops(expr)-1),rascim(expr[-1],op(Args)))
   fi:
   if latx=yes or LATEX_=yes then aexp:= cat("\\{",aexp,"\\}") else aexp:=cat("{",aexp,"}"); fi;
elif type(expr,list) then aexp:=cat("[[",rascim(op(expr),op(Args)),"]]")
  
elif type(expr,string) then aexp:= expr; return aexp;

##handle `=`
elif type(expr,`=`) then
        aexp:= cat(rascim(op(1,expr),op(Args))," = ",rascim(op(2,expr),op(Args)))

elif type(expr,`<`) then
        aexp:=cat(rascim(op(1,expr),op(Args))," < ",rascim(op(2,expr),op(Args)))
elif type(expr,`<=`) then
        if latex=no then
        aexp:=cat(rascim(op(1,expr),op(Args))," <= ",rascim(op(2,expr),op(Args)))
        else
        aexp:=cat(rascim(op(1,expr),op(Args))," \\leq ",rascim(op(2,expr),op(Args))) fi:


elif nops(indets(denom(expr),symbol))>0 or (evalf(denom(expr))>1 and nops(indets(numer(expr),symbol))=0)  then if latex=yes then
                             aexp:=cat("\\frac{",rascim(numer(expr),op(Args)),"}{",rascim(denom(expr),op(Args)),"}") else
                             aexp:=cat("(",rascim(numer(expr),op(Args)),")/(",rascim(denom(expr),op(Args)),")") fi;            
elif type(expr,`^`) then left:=op(1,expr): right:=op(2,expr):        
        if surds=yes and denom(right)<>1 then  
                   if numer(right)=1 then bill:=1 else bill := convert(numer(right),symbol) fi:
                   if denom(right)=2 then sam :="" else sam:=convert(denom(right),string) fi:
                   if latex=yes then aexp:=cat("\\sqrt[",sam,"]{",rascim(left^bill,op(Args)),"}")
                   else
                   aexp:=cat("root(",sam,")(",rascim(left^bill,op(Args)),")"):
                  fi;                                               
        else  
          if  type(left,symbol) or type(left,numeric) then left := rascim(left,op(Args));
              else  if latex = yes then left := cat("{",rascim(left,op(Args)),"}") else left:= cat("(",rascim(left,op(Args)),")") fi fi;
     if latex =yes then aexp:=cat(left,"^{",rascim(right,op(Args)),"}")
      else aexp:= cat(left,"^(",rascim(right,op(Args)),")")
     fi
    fi ;



##handle *
elif type(expr,`*`) then left:=op(1,expr):  right:=convert([seq(op(i,expr),i=2..nops(expr))],`*`):
        
        if not ck1(left,[symbol,numeric,`^`,`*`,list,procedure,function]) then left:=cat("(",rascim(left,op(Args)),")");
           else left:=rascim(left,op(Args)) fi;
        if not ck1(right,[symbol,numeric,`^`,`*`,list,procedure,function]) then right:=cat("(",rascim(right,op(Args)),")")
        elif ck2(right) then right:=rascim(op(1,right)^(-op(2,right)),op(Args));
              if latex=no then return cat(left,"/(",right,")") else return cat("\\frac{",left,"}{",right,"}") fi
        else right:=rascim(right,op(Args)) fi;
        
        if latex=yes then aexp:=cat(left,"\\,",right) else aexp:= cat(left,"\\ ",right) fi

##handle `+`
  elif type(expr,`+`) then aexp:=rascim(op(1,expr),op(Args)): right:=[op(expr)]:
     for i from 2 to nops(right) do
        if SubString(rascim(right[i],op(Args)),1..1)="-" then aexp:=cat(aexp," - ",rascim(-right[i],op(Args)))
                                else aexp:=cat(aexp," + ",rascim(right[i],op(Args)))
        #if sign((right[i]))=1 then aexp:=cat(aexp," + ",rascim(right[i],op(Args))) else
                                 #aexp:=cat(aexp," - ",rascim(-right[i],op(Args)))
        fi; od;       
    
##handle fractions
elif type(expr,algebraic) and denom(simplify(expr))<>1 then left:=numer(simplify(expr)): right:=denom(simplify(expr)):
      if latex=no then aexp:=cat("(",rascim(left,op(Args)),")/(",rascim(right,op(Args)),")")
        else aexp:=cat("\\frac{",rascim(left,op(Args)),"}{",rascim(right,op(Args)),"}") fi:



elif type(expr,indexed) then
           if latex = no then
           aexp:=cat(convert(op(0,expr),string),"_(",seq(cat(convert(op(i,expr),string),","),i=1..nops(expr)));
           aexp:=cat(Chop(aexp),")")
           else
           aexp:=cat(convert(op(0,expr),string),"_{",seq(cat(convert(op(i,expr),string),","),i=1..nops(expr)));
           aexp:=cat(Chop(aexp),"}") fi:
   
##handle functions
elif type(expr,function) then
if op(0,expr)=Paren then aexp:=SubstituteAll(SubstituteAll(convert(op(1,expr),string),"[","("),"]",")");

elif member(op(0,expr),{Lim,Limit}) then
  l:=lhs(op(2,expr)):r:=rhs(op(2,expr)):
  if nops(expr)=3 then if op(3,expr)=right then s:="+" else s:="-" fi fi:;
  if latex=yes then
    if nops(expr)=3 then  
     aexp:= cat("\\displaystyle\\lim_{",rascim(l,op(Args)),"\\rightarrow",rascim(r,op(Args)),"^{",s,"}}\\,",rascim(op(1,expr),op(Args)))
  else
   aexp:= cat("\\displaystyle\\lim_{",rascim(l,op(Args)),"\\rightarrow ",rascim(r,op(Args)),"}\\,",rascim(op(1,expr),op(Args)))
  fi;
else  if nops(expr)=3 then
  aexp:= cat("lim_(",rascim(l,op(Args))," to ",rascim(r,op(Args)),"^(",s,"))\\ ",rascim(op(1,expr),op(Args)))
  else
   aexp:= cat("lim_(",rascim(l,op(Args))," to ",rascim(r,op(Args)),")\\ ",rascim(op(1,expr),op(Args)))
  fi;
 fi:
       

elif latex=yes then
  
   if member(op(0,expr),{ColVec}) then mat:=convert(op(1,expr),list):
       #if op(0,expr)=Syseqn then aexp:="\\left\\\\{\\begin{array}{c} ": esymb:="\\end{array}\\right.":
       #elif op(0,expr)=ColVec then aexp:="\\left(\\begin{array}{c} ": esymb:="\\end{array}\\right)":
       #fi;
       aexp:="\\left(\\begin{array}{c} ": esymb:="\\end{array}\\right)":
       for i from 1 to nops(mat) do  
        aexp:=cat(aexp,rascim(mat[i],op(Args))," \\\\"); od;
       aexp:=cat(Chop(Chop(aexp)),esymb)
   elif member(op(0,expr),{Syseqn}) then mat:=convert(op(1,expr),list):  sam:="rcl":
       if nops(expr)>1 then sam:=convert(op(2,expr),string): if length(sam)=1 then sam:=cat(sam,"c",sam)
          else sam:=cat(Substring(op(2,expr),1..1),"c",Substring(op(2,expr),2..2)) fi; fi;
       if LATEX_=yes then
       aexp:=cat("\\left\\{\\begin{array}{",sam,"} ") else aexp:=cat("\\left\\\\{\\begin{array}{",sam,"} ") fi:
        esymb:="\\end{array}\\right.":
              for i from 1 to nops(mat) do if member(op(0,mat[i]),{`=`,`<`}) then
              bill := cat("& ",convert(op(0,mat[i]),string)," &") elif op(0,mat[i])=`<=` then bill:="& \\leq &"
               else bill:=cat("& \\",convert(op(0,mat[i]),string)," &") fi;  
        aexp:=cat(aexp,rascim(op(1,mat[i]),op(Args)),bill,rascim(op(2,mat[i]),op(Args))," \\\\"); od;
       aexp:=cat(Chop(Chop(aexp)),esymb)


     elif member(op(0,expr),{Mat,Det}) then mat:=convert(op(1,expr),listlist):
          if nops(expr)>1 then
          if length(op(2,expr))=1 then fsymb:=cat(seq(op(2,expr),i=1..nops(mat[1])))
          elif length(op(2,expr))>1 and length(op(2,expr))=nops(mat[1])  then
          fsymb:=op(2,expr) else error "you must format all the columns" fi
          else fsymb:=cat(seq("c",i=1..nops(mat[1])))fi;
          
                
       if op(0,expr)=Det then   aexp:=cat("\\left|\\begin{array}{",fsymb,"} "): esymb:="\\end{array}\\right|":
       elif op(0,expr)=Mat then aexp:=cat("\\left(\\begin{array}{",fsymb,"} "): esymb:="\\end{array}\\right)":
       fi:
       for i from 1 to nops(mat) do
        aexp:=cat(aexp,seq(cat(rascim(mat[i][j],op(Args))," & "),j=1..nops(mat[i])-1),
rascim(mat[i,nops(mat[i])],op(Args))," \\\\"); od;
    aexp:=cat(Chop(Chop(aexp)),esymb)


elif op(0,expr)=Tab then mat:=convert(op(1,expr),listlist):
     if nops(expr)>1 then
          if length(op(2,expr))=1 then fsymb:=cat(seq(op(2,expr),i=1..nops(mat[1])))
          elif length(op(2,expr))>1 and length(op(2,expr))=nops(mat[1])  then
          fsymb:=op(2,expr) else error "you must format all the columns" fi
          else fsymb:=cat(seq("l",i=1..nops(mat[1])))fi;
     aexp:=cat("\\begin{tabular}{",fsymb,"} "): esymb:="\\end{tabular}":
     for i from 1 to nops(mat) do
        aexp:=cat(aexp,seq(cat(rlprint(mat[i][j])," & "),j=1..nops(mat[i])-1),
             rlprint(mat[i,nops(mat[i])])," \\\\"); od;
         aexp:=cat(Chop(Chop(aexp)),esymb)    

elif member(op(0,expr),{RowVec,Pnt}) then
     aexp:="(": if nops(expr)>1 then mat:=convert(expr,list) else mat:=convert(op(1,expr),list) fi;
     for i from 1 to nops(mat) do
        aexp:=cat(aexp,rascim(mat[i],op(Args)),", "); od;
    aexp:=cat(Chop(Chop(aexp)),")")

  
    elif member(op(0,expr),{piecewise,Pcwise}) then  if LATEX_=yes then sam:="\\left\\" else sam:="\\left\\\\" fi:
         aexp:=cat(sam,"{\\begin{array}{ll} ",seq( cat(rascim(op(2*(i-1),expr),op(Args))," &  \\mbox{ if }",rascim(op(2*(i-1)-1,expr),op(Args))," \\\\ "),i=2..iquo(nops(expr),2)+1)):
          if irem(nops(expr),2)=1 then aexp:=cat(aexp,cat(rascim(op(nops(expr),expr))," &  \\mbox{ otherwise. }\\end{array}\\right. "))
          else aexp:= cat(Chop(Chop(aexp))," \\end{array}\\right.") fi;

    elif op(0,expr)=Binomial then
     aexp:=cat("\\left(\\begin{array}{c} ",rascim(op(1,expr))," \\\\ ",rascim(op(2,expr))," \\end{array}\\right)"):

    elif op(0,expr)=Product then
      if nops(expr)=1 then
        aexp:=cat("\\prod ",rasc(op(1,expr),op(Args)))
      elif type(op(2,expr),`=`) then
        if not type(op(2,op(2,expr)),`..`)
          then error "Need range in Product" else
          aexp:=cat("\\prod_{",convert((op(1,op(2,expr)))=op(1,op(2,op(2,expr))),string),"}^{",convert(op(2,op(2,op(2,expr))),
string),"}",rascim(op(1,expr),op(Args)))
        fi
      else
          aexp:= cat("\\prod_{",rascim(op(2,expr),op(Args)),"}\\,",rascim(op(1,expr),op(Args)))
      fi

    elif op(0,expr)=Sum then
         if nops(expr)=1 then aexp:=cat("\\sum ",rascim(op(1,expr),op(Args)))
         elif type(op(2,expr),`=`) then
          if not type(op(2,op(2,expr)),`..`)
          then error "Need range in Sum" else
          aexp:=cat("\\sum_{",rascim((op(1,op(2,expr)))=op(1,op(2,op(2,expr))),op(Args)),"}^{",rascim(op(2,op(2,op(2,expr))),
op(Args)),"}",rascim(op(1,expr),op(Args)))
        fi
      else
          aexp:= cat("\\sum_{",rascim(op(2,expr),op(Args)),"}",rascim(op(1,expr),op(Args)))
      fi;       

    elif op(0,expr)=Int then
      if nops(expr)=1 then ;
        aexp:=cat("\\int ",rascim(op(1,expr),op(Args)));
      elif type(op(2,expr),`=`) then
        if not type(op(2,op(2,expr)),`..`)
          then error "Need range in Int" else
          aexp:=cat( "\\int_{",rascim(op(1,op(2,op(2,expr)))),"}^{",rascim(op(2,op(2,op(2,expr)))),"}",rascim(op(1,expr),op(Args)),"\\,d ",rascim(op(1,op(2,expr))))
        fi
      else
          aexp:= cat("\\int ",rascim(op(1,expr),op(Args)),"\\, d ",rascim(op(2,expr)))
      fi
    elif op(0,expr)=Diff then  
        if ck1(op(1,expr),[`+`])
             then aexp:=cat("\\frac{d}{d ",rascim(op(2,expr)),"}\\ (",rascim(op(1,expr),op(Args)),")")
             else aexp := cat("\\frac{d}{d ",rascim(op(2,expr)),"}\\ ",rascim(op(1,expr),op(Args)))
        fi;
elif op(0,expr)=Pdiff then
      if nops(expr)=2 then
          l:="\\partial";
          r:=cat("\\partial ",rascim(op(2,expr)));
      elif nops(expr)>2 then
          s:=0: for j from 2 to nops(expr) do if type(op(j,expr),`^`) then s:=s+op(2,op(j,expr)) else s:=s+1 fi od:
          l:=cat("\\partial^{",convert(s,string),"}");
          r:=cat(seq(cat("\\partial ",rascim(op(j,expr))),j=2..nops(expr)));
      else error "Pdiff needs a variable to differentiate"
      fi;  
      if ck1(op(1,expr),[`+`])
         then aexp:=cat("\\frac{",l,"}{",r,"}\\ (",rascim(op(1,expr),op(Args)),")")
      else aexp := cat("\\frac{",l,"}{",r,"}\\ ",rascim(op(1,expr),op(Args)))
      fi;
        

  elif  member(op(0,expr),{ln,sin,cos,tan,arccos,arcsin,arctan,exp}) then
     aexp:=cat("\\",convert(op(0,expr),string),"(",rascim(op(1,expr)),")")
    else aexp := cat(`latex/print`(expr))
    fi
  
  elif latex=no then
   if  member(op(0,expr),{ln,sin,cos,tan,arccos,arcsin,arctan,exp}) then
     aexp:=cat("text(",convert(op(0,expr),string),")(",rascim(op(1,expr),op(Args)),")")

elif op(0,expr)=Pdiff then
      if nops(expr)=2 then
          l:=" del ";
          r:=cat(" del ",rascim(op(2,expr)));
      elif nops(expr)>2 then
          s:=0: for j from 2 to nops(expr) do if type(op(j,expr),`^`) then s:=s+op(2,op(j,expr)) else s:=s+1 fi od:
          l:=cat("del^(",convert(s,string),")");
          r:=cat(seq(cat(" del ",rascim(op(j,expr))),j=2..nops(expr)));
      else error "Pdiff needs a variable to differentiate"
      fi;  
      if ck1(op(1,expr),[`+`])
         then aexp:=cat("\\frac{",l,"}{",r,"}\\ (",rascim(op(1,expr),op(Args)),")")
      else aexp := cat("\\frac{",l,"}{",r,"}\\ ",rascim(op(1,expr),op(Args)))
      fi;


     elif member(op(0,expr),{Syseqn,ColVec}) then if nops(expr)>1 then mat:=convert(expr,list) else mat:=convert(op(1,expr),list): fi;
       if op(0,expr)=Syseqn then aexp:="{": esymb:=":}":
       elif op(0,expr)=ColVec then aexp:="(": esymb:=")":
       fi;
       for i from 1 to nops(mat) do  
        aexp:=cat(aexp,"(",rascim(mat[i],op(Args)),"),"); od;
       aexp:=cat(Chop(aexp),esymb)

     elif member(op(0,expr),{Mat,Det,Tab}) then mat:=convert(op(1,expr),listlist):     
       if op(0,expr)=Det then   aexp:="|": esymb:="|":
       elif op(0,expr)=Mat then aexp:="(": esymb:=")":
       elif op(0,expr)=Tab then aexp:="{:":  esymb:=":}":
       fi:
       for i from 1 to nops(mat) do
        aexp:=cat(aexp,"(",seq(cat(rascim(mat[i][j],op(Args))," , "),j=1..nops(mat[i])-1),rascim(mat[i,nops(mat[i])],op(Args)),"),"); od;
    aexp:=cat(Chop(aexp),esymb)

    

elif member(op(0,expr),{RowVec,Pnt}) then
     aexp:="(": if nops(expr)>1 then mat:=convert(expr,list) else mat:=convert(op(1,expr),list) fi;
     for i from 1 to nops(mat) do
        aexp:=cat(aexp,rascim(mat[i],op(Args)),","); od;
    aexp:=cat(Chop(aexp),")")

  
    elif member(op(0,expr),{piecewise,Pcwise}) then
         aexp:=cat(" {",seq( cat("(",rascim(op(2*(i-1),expr),op(Args)),",",text("  if "),
rascim(op(2*(i-1)-1,expr),op(Args)),"),"),i=2..iquo(nops(expr),2)+1)):
          if irem(nops(expr),2)=1 then aexp:=cat(aexp,cat("(",rascim(op(nops(expr),expr)),",",text(" otherwise."),"):}"))
          else aexp:= cat(Chop(aexp)," :}") fi;

    elif op(0,expr)=Binomial then aexp:=cat("((",rascim(op(1,expr)),"),(",rascim(op(2,expr)),"))"):

    elif op(0,expr)=Product then
      if nops(expr)=1 then
        aexp:=cat(" Pi ",rascim(op(1,expr),op(Args)))
      elif type(op(2,expr),`=`) then
        if not type(op(2,op(2,expr)),`..`)
          then error "Need range in Product" else
          aexp:=cat(" Pi_(",convert(op(1,op(2,op(2,expr))),string),")^(",convert(op(2,op(2,op(2,expr))),
string),")",rascim(op(1,expr),op(Args)))
        fi
      else
          aexp:= cat(" Pi ",rascim(op(1,expr),op(Args)))
      fi

    elif op(0,expr)=Sum then
      if nops(expr)=1 then
        aexp:=cat(" sum ",rascim(op(1,expr),op(Args)));
      elif type(op(2,expr),`=`) then
        if not type(op(2,op(2,expr)),`..`)
          then error "Need range in Sum" else
          aexp:=cat(" sum_(",convert(op(1,op(2,expr)),string)," = ",convert(op(1,op(2,op(2,expr))),string),")^(",convert(op(2,op(2,op(2,expr))),
string),")",rascim(op(1,expr),op(Args)))
        fi
      else
          aexp:= cat(" sum ",rascim(op(1,expr),op(Args)))
      fi
  
    elif op(0,expr)=Int then
      if nops(expr)=1 then aexp:=cat(" int ",rascim(op(1,expr),op(Args)))
      elif type(op(2,expr),`=`) then
        if not type(op(2,op(2,expr)),`..`)
          then error "Need range in Int" else
          aexp:=cat(" int_(",convert(op(1,op(2,op(2,expr))),string),")^(",convert(op(2,op(2,op(2,expr))),
string),")",rascim(op(1,expr),op(Args)),"\\ d ",convert(op(1,op(2,expr)),string))
        fi
      else
          aexp:= cat(" int ",rascim(op(1,expr),op(Args)),"\\ d ",convert(op(2,expr),string))
      fi
    elif op(0,expr)=Diff then  
        if ck1(op(1,expr),[`+`])
             then aexp:=cat("d/(d ",rascim(op(2,expr),op(Args)),")\\ (",rascim(op(1,expr),op(Args)),")")
             else aexp := cat("d/(d ",rascim(op(2,expr),op(Args)),")\\ ",rascim(op(1,expr),op(Args)))
        fi;
    else aexp:=convert(expr,string);
  
   fi
     
  else aexp:=cat(`latex/print`(expr))
  fi   
elif type(expr,algebraic) then  aexp := cat(`latex/print`(expr))
fi;
if latex=no then
aexp:=RegSubs( "({\\\\it ([^}]*)})"="\\2",aexp );
aexp:= SubstituteAll(aexp,"\\it"," ");
aexp:= SubstituteAll(aexp,"\\!"," ");
aexp:= SubstituteAll(aexp,"\\,"," ");
aexp:=SubstituteAll(aexp,"*","\\ ");
#aexp:= SubstututeAll(aexp,"\\backslash"," ");
aexp:= SubstituteAll(aexp,"\\right"," ");
aexp:= SubstituteAll(aexp,"\\left"," ");
else
aexp:=SubstituteAll(aexp,"*","\\, ");#print("Hello"):
fi;

aexp:=SubstituteAll(aexp,"\\int","\\displaystyle\\int");
aexp:=SubstituteAll(aexp,"\\sum","\\displaystyle\\sum");
aexp:=SubstituteAll(aexp,"`","");
aexp:=RegSubs( "(\\\\text {{\\\\tt ([^}]*)}})"="\\ \\2\\ ",aexp );
aexp:=RegSubs( "(\\\\mbox {{\\\\tt ([^}]*)}})"="\\ \\2\\ ",aexp );
if parens=yes then
aexp:=SubstituteAll(aexp,"[[","(");
aexp:=SubstituteAll(aexp,"]]",")");
else
aexp:=SubstituteAll(aexp,"[[","");
aexp:=SubstituteAll(aexp,"]]","");
fi
    
 end use;
aexp;
end:
###end rascim

big:="\\displaystyle":

tex:=t->
  cat("\\mbox{",t,"}") :

text:=t->
  cat(" text{",t,"}") :

rel:= proc(a)
 local cnv,tr;
 cnv := table([]);
cnv[leq]:=["\\leq "," <= "]:cnv[lt]:=[" < "," <= "]:
cnv[geq]:=["\\geq "," >= "]:cnv[gt]:=[" > "," > "]:
cnv[neq]:=["\\neq "," <> "]:
 if LATEX_=yes then cnv[a][1] else cnv[a][2] fi end:

ltlt:=proc(a,r1,b,r2,c)
   if LATEX_=yes then [cat("$",convert(a,string),rel(r1),convert(b,string),rel(r2),convert(c,string),"$")]
   else rlprint("`",convert(a,string),rel(r1),convert(b,string),rel(r2),convert(c,string),"`") fi
end:

la:=proc()
local st,l,lst;
lst:=[args]:
st:="$":
for l in lst do
 st:=cat(st,rascim(l,Latex=yes))
od;
st:=cat(st,"$");
if st="$$" then NULL else st fi;
end:

>    ra:=proc()
local st,l,lst;
lst:=[args]:
st:="`":
for l in lst do
 st:=cat(st,rascim(l,Latex=no))
od;
st:=cat(st,"`");
if st="``" then NULL else st fi;  
end:

rla:=proc()
 if LATEX_=yes then la(args) else ra(args) fi:
end:

###asciimat  1/11/09
asciimat := proc()
  local i,j,n,m,mat,lst,row,front,back,standalone,defaults,opts,tmp;
    if member(args[1],{Help,"Help",Help=yes,"Help=yes"}) then
    mcprint("asciimat(list) returns an expression sequence of strings and symbols which will
    produce a matrix in asciimath in tagit when in a bracketed line.
    Options
    Standalone=yes  encloses the matrix in ` `
    Frontsymbol = \"(\" change to \"[\", \"{\", \"|\", or \"\",  as needed
    Backsymbol= \")\"  change to \"[\", \"{\", \"|\", or \"\",  as needed
      Note: \"{:\" and \":}\" are invisible symbols");
    return NULL fi;
 defaults:=Frontsymbol="(",Backsymbol=")",Standalone=yes;      
 opts:=subs([op(select(type,[args],`=`)),defaults],[Frontsymbol,Backsymbol,Standalone]);
  front:=opts[1]:
  back:=opts[2]:
  if opts[3]=yes then standalone:="`" else standalone :="" fi:
   
  lst:=args[1];
   if type(lst,list) then
   n:=nops(lst);
   if type(lst[1],list) then
    m:=nops(lst[1]):
   for i from 2 to n do if nops(lst[i])<>m then return NULL fi:   od;      
   else
   tmp:=NULL:
   for i from 1 to n do
    tmp:=tmp,[lst[i]] od:
   lst:=[tmp]:  m:= 1: fi; fi;
 
 mat := cat(standalone,front);
  for i from 1 to n do
  row:= "(";
  for j from 1 to m do
  if j > 1 then row := row,"," fi; row:=row,lst[i][j] od;
  if i < n then row := row,")," else row:=row,")" fi:
  mat := mat,row;
  od;
  if back="" and front="{" then back:=":}" fi:
   mat:=mat,cat(back,standalone);
  mat end:
 #end asciimat

###mcprint
mcprint:= proc()
 local fmt,fmtnl,ARGS,c;
 c:=proc(g)
  convert(g,string)
 end:
 ARGS:=map(c,[args]):
 if nops(ARGS)=0 then
  ARGS:=[""]
 fi;
 fmt := "%s";
 fmtnl:="%s\n":
 printf(cat(seq(fmt,i=1..nops(ARGS)-1),fmtnl),seq(ARGS[j],j=1..nops(ARGS)));
end:
###end mcprint

#
MCdefaults:= proc()
global BOXLENGTH_,ERROR_,MAGIC_,MCTOOLS_,PNUM_,WBOX_,STANDARDS_,RNGCHK_,CHK_;
local Args,ARGS,defaults,vals,help;
 defaults:=Help=no,Magic=eval(MYMAGIC_),Error=`.05`,Check=on,RngChk=[.1,1],Boxlength=15,Wbox=15,Standards=yes;  
vals:= subs([ op(select(type,[args],`=`)),defaults],[Help,Magic,Error,Boxlength,Wbox,Standards,RngChk,Check]);
help:=vals[1];
if help=yes then mcprint("
MCdefaults()  sets the default values of some global variables
options:
Magic = MYMAGIC_  # change this to your mathclass guid
Boxlength = 15 # change this to whatever size numerical entry box you want
Error = `-0.05`  # the allowable relative error in giving a numerical or function answer
RngChk = [.1,1] # the range over which a function is evaluated
Check=on #toggles checking for the precision and domain check of function testing
Wbox = 15 # the default size of word box in answer formats AW and ATcross");
RETURN(NULL) fi;
MAGIC_ := vals[2]:  # set this to your account number if you have hidden sections
BOXLENGTH_:= vals[4]: # the default length of an entrybox for AC
ERROR_ := vals[3]: # the default precision required for answer
RNGCHK_:=vals[7]:#the default range check
CHK_:=vals[8]:#toggle to turn off/on checking relative error and function range  
PNUM_ := NULL: # if set to integer, numbers the problems
STANDARDS_:=vals[6]:  # set to no if you don't want standards in the problem.
MCTOOLS_:=map(convert,[addlink, addsectionhint, ah_, addvlink,  ARRW, av_, Axes,
       brak,  CARR, colors, DL, DV, fill, generator, GP, GP2, GP3,        hashang,  Header, htmltable, Line, lineit,
       maketable, mctools, mcpiecewise, mcprint, MM,
       PA, PARAMS, PC, PP, printdata, PT, RANDANS, roundto,roundit,
       show_answers, symbolize, tableit, tagit, vspace, hspace,zipit,filter7],string):  # is set to the list of mctools words at end
# LATEX_ := no:  #set to yes for latex hardcopy homework.
WBOX_:= vals[5]:  # the default length of an entry box used in AW, AF, and AE
readlib(spline):
ver,[Help=help,Magic=MAGIC_,Error=ERROR_,Boxlength=BOXLENGTH_,Wbox=WBOX_,Standards=STANDARDS_,Check=CHK_,RngChk=RNGCHK_];
end:

>    eval(MCdefaults());

>   

>   

>   
###brak
brak := proc()
 if not LATEX_=yes then
  ["_brk_\n"]
 else
  ["\\par\n"]
 fi
end:
###end brak


###vspace
vspace:= proc(n)
 local a,i,defaults,opts,help,star,height;
defaults:=Help=no,Star=no,Height=24;
opts:=  selectremove(type,[args],`=`);
 opts:=subs([op(opts[1]),defaults],[Help,Star,Height]):
help := opts[1]:star:=opts[2]: height:=opts[3]:
 if help=yes then
 mcprint("vspace(n)  returns n brks if LATEX_=no, and vspace{Height*n pt} if not.
 options:  
 Help=yes to return this message
 Star=yes to output vspace* instead of vspace: default is Star=no
 Height=24   set Height=\"1.3in\" to get vspace 1.3 inch"):
 RETURN(NULL) fi:
 if star=yes then star := "*" else star := "" fi;
 if not type(height,string) then height := cat(convert(height*n,symbol)," pt") fi;
 if not LATEX_ = yes then
  cat(seq("_brk_",i=1..n),"\n")
 else
  [cat("\\vspace",star,"{",height,"}")]
 fi
end:
###end vspace

## hspace
hspace:= proc(n)
 local a,i,defaults,opts,help,star,width;
defaults:=Help=no,Star=no,Width=12;
opts:=  selectremove(type,[args],`=`);
 opts:=subs([op(opts[1]),defaults],[Help,Star,Width]):
help := opts[1]:star:=opts[2]: width:=opts[3]:
 if help=yes then
 mcprint("hspace(n)  returns n brks if LATEX_=no, and hspace{Height*n pt} if not.
 options:  
 Help=yes to return this message
 Star=yes to output hspace* instead of hspace: default is Star=no
 Width=24   set Width=\"1.3in\" to get hspace 1.3 inch"):
 RETURN(NULL) fi:
 if star=yes then star := "*" else star := "" fi;
 if not type(width,string) then width := cat(convert(width*n,symbol)," pt") fi;
 if not LATEX_ = yes then
  cat(seq("amp_nbsp;",i=1..n))
 else
  [cat("\\hspace",star,"{",width,"}")]
 fi
end:

###PARAMS
PARAMS:=proc(Defaults,Args)
 local Ndefs,Nargs,In_args,j,k,Not_in_args,PLOTOPTIONS,Nopts,
       In_PLOTOPTIONS,ARGS,NARGS,In_ARGS:
 PLOTOPTIONS:=[adaptive,axes,axesfont,color,coords,discont,filled,font,labels,
       labeldirections,labelfont,legend,linestyle,numpoints,sample,scaling,
       style,symbol,symbolsize,thickness,tickmarks,title,titlefont,
       view,xtickmarks,ytickmarks]:
 Nargs:=nops(Args):
 Ndefs:=nops(Defaults):
 Nopts:=nops(PLOTOPTIONS):
 In_PLOTOPTIONS:=NULL:
 for j from 1 to Nargs do
  for k from 1 to Nopts do
   if convert(lhs(Args[j]),string) = convert(PLOTOPTIONS[k],string) then
    In_PLOTOPTIONS:=In_PLOTOPTIONS,Args[j]:
   fi:
  od:
 od:
 ARGS:=[op({op(Args)} minus {In_PLOTOPTIONS})]:
 NARGS:=nops(ARGS):
 In_ARGS:=NULL:
 for j from 1 to NARGS do
  for k from 1 to Ndefs do
   if convert(lhs(ARGS[j]),string) = convert(lhs(Defaults[k]),string) then
    In_ARGS:=In_ARGS,Defaults[k]:
   fi:
  od:
 od:
 Not_in_args:=[op({op(Defaults)} minus {In_ARGS})]:
 [op(ARGS),op(Not_in_args)],[In_PLOTOPTIONS]:
end:
###end vspace

###PT
PT:= proc(LOCATION,TXT)
 local Args,defaults,ARGS,FONTSIZE,CLR,PLOTOPTIONS:
 defaults:=location=[0,0], fontsize=14,clr=black:
 Args:=seq([args][j],j=3..nargs):
 ARGS:=PARAMS([defaults],[Args])[1]:
 PLOTOPTIONS:=op(PARAMS([defaults],[Args])[2]):
 FONTSIZE:=subs(ARGS,fontsize):
 CLR:=subs(ARGS,clr):
 if nops(LOCATION)=3 then
  plots[textplot3d]([LOCATION[1],LOCATION[2],LOCATION[3],TXT],font=[HELVETICA,FONTSIZE],      color=CLR,PLOTOPTIONS)
 else
  plots[textplot]([LOCATION[1],LOCATION[2],TXT],font=[HELVETICA,FONTSIZE],      color=CLR,PLOTOPTIONS)
 fi:
end:
###end PT

###colors
colors := proc()
 local Showthem,CLRS, SIZE, STEP, colorlist, i, ARGS, defaults:
 defaults:=showthem=`yes`:
 ARGS:=PARAMS([defaults],[args]):
 Showthem:=subs(ARGS,showthem):
 if Showthem=`no` then
  mcprint("aquamarine black blue navy coral cyan, brown gold green, gray, grey,
    khaki, magenta, maroon, orange, pink, plum, red, sienna, tan,turquoise, violet, wheat,
    white, yellow.");
  mcprint(" "):
  mcprint("In addition one can define colors. See help on \"plot,color\". "):
 else
  colorlist:=[black,  blue, navy, coral, cyan, brown, gold, green, gray, grey, khaki,
    magenta, maroon, orange, pink, plum, red, sienna, tan, turquoise, violet,
    wheat, white, yellow]:
  plots[display](matrix([seq([seq(
  plots[display](plottools[polygon]([[-1,-1],[1,-1],[1,1],[-1,1]],color=colorlist[j+(i-1)*6]),           PT([0,-1.3],colorlist[j+(i-1)*6],fontsize=12),axes=none),j=1..6)],i=1..4)]),
    scaling=constrained)
 fi:
end:
###end colors

###DL
DL:=proc(A,b)
 local Thknss,Styl,Clr,ARGS,defaults,Args,lsf,rsf,TMP,Hashlocation,
       Hashnum,lngth,Hashspacing,prp,midpt,hashmarks,Hashlength,
       Hashrotangle,PLOTOPTIONS,B:
 defaults:=thknss=2,styl=1,clr=blue,rightshrinkfactor=0,leftshrinkfactor=0,
       hashnum=0,hashlength=.3,hashlocation=.5,hashspacing=.1,hashrotangle=0:
 Args:=seq([args][i],i=3..nargs):
 ARGS:=PARAMS([defaults],[Args])[1]:
 PLOTOPTIONS:=op(PARAMS([defaults],[Args])[2]):
 Thknss:=subs(ARGS,thknss):
 Styl:=subs(ARGS,styl):
 Clr:=subs(ARGS,clr):
 lsf:=subs(ARGS,leftshrinkfactor):
 rsf:=subs(ARGS,rightshrinkfactor):
 Hashnum:=subs(ARGS,hashnum):
 Hashlocation:=subs(ARGS,hashlocation):
 Hashspacing:=subs(ARGS,hashspacing):
 Hashlength:=subs(ARGS,hashlength):
 Hashrotangle:=evalf(subs(ARGS,hashrotangle)):
if A=b then if nops(A)=3 then B := b+[0,.01,0] else B := b+[0,.01] fi else B := b  fi:
 if nops(A) =3 and nops(B)=3 then
  TMP:=plots[polygonplot3d]([(1-lsf)*A+lsf*B,rsf*A+(1-rsf)*B],style = LINE,            linestyle=Styl,thickness=Thknss,color=Clr,PLOTOPTIONS):
  plots[display]([TMP]):
 elif nops(A) =2 and nops(B)=2 then
  prp:= expand(B-A):
  lngth:=evalf(1/sqrt(prp[1]^2+prp[2]^2)):
  prp:=(cos(Hashrotangle) + I*sin(Hashrotangle))* (lngth*(prp[2]-I*prp[1])):
  prp:=evalf(convert(expand(prp),list)):
  midpt:=expand(.5*(A+B)):
  if ((Hashnum mod 2) = 0) then
   hashmarks:= seq(plots[polygonplot](
     [A+(Hashlocation-(Hashnum/2-1)*Hashspacing/2 +j*Hashspacing)*(B-A) -      
     .5*Hashlength*prp,A+(Hashlocation-(Hashnum/2-1)*Hashspacing/2+j*Hashspacing)*(B-A) +     
     .5*Hashlength*prp],linestyle=1,thickness=1,color=black),j=0..Hashnum-1):
  elif ((Hashnum mod 2) = 1) then
   hashmarks:= seq(plots[polygonplot](
     [A+(Hashlocation+j*Hashspacing)*(B-A) -           .5*Hashlength*prp,A+(Hashlocation+j*Hashspacing)*(B-A) +           .5*Hashlength*prp],linestyle=1,thickness=1,color=black),j=-(Hashnum-1)/2..(Hashnum-1)/2):
  fi:
  TMP:=plots[polygonplot]([(1-lsf)*A+lsf*B,rsf*A+(1-rsf)*B],style = LINE,        linestyle=Styl,thickness=Thknss,color=Clr,PLOTOPTIONS):
  plots[display]([TMP,hashmarks]):
 else RETURN(`bad data`)
fi:
end:
###end DL

###GP
GP:=proc()
 local V,H,axes,i,LLcorner,Width,Height,TMFont,Res,Defaults,Axescolor,
       ARGS,defaults,PLOTOPTIONS:
 defaults:=llcorner=[-5,-5],width=10,height=10,resolution=2,tickmarkfont=12,axescolor=red:
 ARGS:=PARAMS([defaults],[args])[1]:
 PLOTOPTIONS:=op(PARAMS([defaults],[args])[2]):
 LLcorner:=subs(ARGS,llcorner):
 Width:=subs(ARGS,width):
 Height:=subs(ARGS,height):
 Res:=subs(ARGS,resolution):
 TMFont:=subs(ARGS,tickmarkfont):
 Axescolor:=subs(ARGS,axescolor):
 V := seq(plot([[LLcorner[1]+i/Res,
  LLcorner[2]],[LLcorner[1]+i/Res,LLcorner[2]+Height]],
 color=black,PLOTOPTIONS),i=0..Width*Res):
 axes:=DL([LLcorner[1],0],[LLcorner[1]+Width,0],thknss=3,styl=1,clr=Axescolor),
   DL([0,LLcorner[2]],[0,LLcorner[2]+Height],thknss=3,styl=1,clr=Axescolor):

>     H :=seq(plot([[LLcorner[1] ,LLcorner[2]+i/Res],
   [LLcorner[1]+Width,LLcorner[2]+i/Res]],color=black),
   i=0..Height*Res):
 if TMFont=`NTM` then
  plots[display]([V,H],xtickmarks =[], ytickmarks =[]):
 elif TMFont=0 then
  plots[display]([V,H],xtickmarks =[], ytickmarks =[],axes=none):
 else
  plots[display]([axes,V,H], xtickmarks =[seq(i, i=LLcorner[1]..LLcorner[1]+Width)],
    ytickmarks = [seq(i, i=LLcorner[2]..LLcorner[2]+Height)], axesfont=[HELVETICA,TMFont]):
 fi:
end:
###end GP

###GP2
GP2:=proc()
 local Args,ARGS,defaults,vals,V, H, i,gopts;
 defaults:=llhc  = [-5,-5],width=10,height=10,xres=1,yres=1,clrs=[black,black],
   xlabl=`x`, ylabl=`y`,TMfont=NTM,thkns=[1,1]:
 Args:=[llhc, width, height, xres,yres,clrs,xlabl,ylabl, TMfont,thkns];
 ARGS:=PARAMS([defaults],[args]):
 vals := subs(ARGS[1],Args);
 gopts:=op(ARGS[2]);
 V := plot([seq(
     [[vals[1][1] + i*vals[4], vals[1][2]], [vals[1][1] + i*vals[4], vals[1][2] +
     vals[3]]],i = 0 .. vals[2]/vals[4])],color = vals[6][1],thickness=vals[10][1]);
 H := plot([seq(
     [[vals[1][1], vals[1][2] + i*vals[5]], [vals[1][1] + vals[2], vals[1][2] +
     i*vals[5]]],i = 0 .. vals[3]/vals[5])],color = vals[6][2],thickness=vals[10][2]);
 if vals[9] = NTM then
  plots[display]([V, H],xtickmarks = [seq(vals[1][1]+i*vals[4],i=0..vals[2]/vals[4])],
     ytickmarks = [seq(vals[1][2]+i*vals[5],i=0..vals[3]/vals[4])],gopts)
 elif vals[9] = 0 then
  plots[display]([V, H], xtickmarks = [], ytickmarks = [], axes = none,gopts)
 else
  plots[display]([V, H],labels=[vals[7],vals[8]], xtickmarks =
   [seq(vals[1][1]+i*vals[4],i=0..vals[2]/vals[4])], ytickmarks =
   [seq(vals[1][2]+i*vals[5],i=0..vals[3]/vals[5])],
   axesfont = [HELVETICA, vals[9]],
  labelfont=[HELVETICA,vals[9]],gopts)
 fi
end:
###end GP2

###GP3
GP3:=proc()
local Args,ARGS,defaults,vals,V, H, K, i,j,levs,verts,gopts;
defaults:=llhc= [0,0,0],width=10,height=10,depth= 10, xres=10/3,yres=10/3, zres = 10/3,
  clrs =[black,red,blue],xlabl=`x`, ylabl=`y`,zlabl = `z`, TMfont=NTM,thkns=[1,1,1]:
Args:=[llhc, width, height,depth, xres,yres,zres,clrs,xlabl,ylabl, zlabl,TMfont,thkns];
ARGS:=PARAMS([defaults],[args]):
vals := subs(ARGS[1],Args);
gopts:=op(ARGS[2]);
levs := NULL:
for j from 0 to vals[4]/vals[7] do
 levs := levs, seq(
    [[vals[1][1] + i*vals[5], vals[1][2],vals[1][3]+j*vals[7]], [vals[1][1] +
    i*vals[5], vals[1][2] + vals[3],vals[1][3]+j*vals[7]]],
    i = 0 .. vals[2]/vals[5]) :

>    od:
V := plots[polygonplot3d]({levs},style=wireframe,color = vals[8][1],thickness=vals[13][1]);
levs := NULL:
for j from 0 to vals[4]/vals[7] do
 levs := levs, seq(
   [[vals[1][1], vals[1][2] + i*vals[6] ,vals[1][3]+j*vals[7]], [vals[1][1] + vals[2],    vals[1][2] + i*vals[6],vals[1][3]+j*vals[7]]],
   i = 0 .. vals[3]/vals[6]) :

>    od:
H := plots[polygonplot3d]({levs},style=wireframe,color = vals[8][2],thickness=vals[13][2]);
verts := NULL:
for i from 0 to vals[2]/vals[5] do
 for j from 0 to vals[3]/vals[6] do
  verts := verts,[[vals[1][1]+i*vals[5],vals[1][2]+j*vals[6],vals[1][3]],
   [vals[1][1]+i*vals[5],vals[1][2]+j*vals[6],vals[1][3]+vals[4]]]:
  K := plots[polygonplot3d]({verts},style=wireframe,color = vals[8][3],thickness=vals[13][3])   od
od;
if vals[12] = NTM then
 plots[display]([V,H,K],tickmarks = map(round,[vals[2]/vals[5],vals[3]/vals[6],
  vals[4]/vals[7]]),axes=normal,gopts)
elif vals[12] = 0 then
 plots[display]([V, H,K],axes = none,gops)
else
 plots[display]([V, H,K],labels=[vals[9],vals[10],vals[11]],
  tickmarks = [vals[2]/vals[5],  vals[3]/vals[6], vals[4]/vals[7]] ,
  axesfont = [HELVETICA, vals[12]],
 labelfont=[HELVETICA,vals[12]],axes=normal,gopts)
fi
end:
###end GP3

>    ###MM
MM := proc()
local Args,ARGS,defaults,vals,f,step,gopts,x,i;
 f := proc(t)
  plot((x/t)^2,x=-1..1)
 end;
 defaults:=partslist=f,tinter=[1,2],numframes=5,speed=1;  
 Args:=[partslist,tinter,numframes,speed];
 ARGS:=PARAMS([defaults],[args]):
 vals := subs(ARGS[1],Args);  
 step := (vals[2][2]-vals[2][1])/(vals[3]-1):
 gopts :=insequence=true,scaling=constrained,op(ARGS[2]);  
 plots[display]([seq(plots[display](
  vals[1](vals[2][1]+floor(i/vals[4])*step)),i=0..vals[4]*(vals[3]-1))],gopts)
end:
###end MM

###PP
PP:=proc(Location,Radius)
 local Args,f,defaults,ARGS,Clr,sf,PLOTOPTIONS:
 defaults:= clr=blue,scalefactor=1:
 Args:=seq([args][j],j=3..nargs):
 ARGS:=PARAMS([defaults],[Args]):
 PLOTOPTIONS:=op(PARAMS([defaults],[Args])[2]):
 Clr:=subs(ARGS,clr):
 sf:=subs(ARGS,scalefactor):
 f:=plottools[transform]((x,y)->
  [Location[1]+x,Location[2]+y*sf]):
 plots[display](f(plottools[disk]([0,0],Radius,color=Clr,PLOTOPTIONS)))
end:
###end PP

###ARRW
ARRW:=proc()
 local Dhgap,Length,Doublearrowtxt,Fontsize,Txtclr,TXT,TMP,Arrowtype,
       Tail,Head,Headwidth,Headlength,Shaftthickness,Clr,defaults,ARGS,PLOTOPTIONS:
 defaults:=tail=[0,0],head=[1,2],headwidth=3,headlength=4,shaftthickness=.03,
       clr=green,arrowtype=`DH`,doublearrowtxt="texthere",fontsize=16,
       txtclr=black,dhgap=1/3:
 ARGS:=PARAMS([defaults],[args]):
 PLOTOPTIONS:=op(PARAMS\([defaults],[args])[2]):
 Tail:=subs(ARGS,tail):
 Head:=subs(ARGS,head):
 Headwidth:=subs(ARGS,headwidth):
 Headlength:=subs(ARGS,headlength):
 Shaftthickness:=subs(ARGS,shaftthickness):
 Clr:=subs(ARGS,clr):
 Arrowtype:=subs(ARGS,arrowtype):
 Doublearrowtxt:=subs(ARGS,doublearrowtxt):
 Fontsize:=subs(ARGS,fontsize):
 Txtclr:=subs(ARGS,txtclr):
 Dhgap:=subs(ARGS,dhgap):
 Length:=sqrt((Head-Tail)[1]^2 +(Head-Tail)[2]^2):
 TXT:=PT(.5*(Head+Tail),Doublearrowtxt,fontsize=Fontsize,clr=Txtclr,PLOTOPTIONS):
 if (Arrowtype = `SH`) then
  TMP:=plottools[arrow](Tail,Head,Shaftthickness*Length,
   Headwidth*Length*Shaftthickness,Headlength*Length*Shaftthickness,
   color=Clr,PLOTOPTIONS):
 elif  (Arrowtype = `DH`) then
  TMP:=plottools[arrow](Tail+(1-Dhgap)/2*(Head-Tail),Tail,
   Shaftthickness*Length,Headwidth*Length*Shaftthickness,
   Headlength*Length*Shaftthickness,color=Clr,PLOTOPTIONS),
  plottools[arrow](Head+(1-Dhgap)/2*(Tail-Head),Head,
   Shaftthickness*Length,Headwidth*Length*Shaftthickness,
   Headlength*Length*Shaftthickness,color=Clr,PLOTOPTIONS):
 fi:
 plots[display]([TMP,TXT]);
end:
###end ARRW

###CARR
CARR := proc()
 local Args,ARGS,defaults,vals,gopts,f,k,i,j,n,di,len,radi,x,y,z,
       band,z0,z1,dir,A,B,C,d;
 f := proc(t)
  plot((x/t)^2,x=-1..1)
 end;
 defaults:=pts=[[0,0,0],[1,0,0],[1,1,0],[1,1,1]],clr=gray,rad=.02,
    hdlen=.2,hdwid=.1,spltp=[cubic,cubic,cubic],mesh=8;  
 Args:=[pts,clr,rad,hdlen,hdwid,spltp,mesh];
 ARGS:=PARAMS([defaults],[args]):
 vals := subs(ARGS[1],Args);
 gopts:=op(ARGS[2]);  
 n := nops(vals[1]);
 di := nops(vals[1][1]);
 if di = 3 then
  len := 0:
  for i from 2 to n do
   len := len+ evalf(sqrt(sum((vals[1][i][j]-vals[1][i-1][j])^2,j=1..di)))
  od:
  x :=  unapply(spline([seq(i,i=0..n-1)],
    [seq(vals[1][i][1],i=1..n)],t,vals[6][1]),t):
  y :=  unapply(spline([seq(i,i=0..n-1)],
    [seq(vals[1][i][2],i=1..n)],t,vals[6][2]),t):
  z :=  unapply(spline([seq(i,i=0..n-1)],
    [seq(vals[1][i][3],i=1..n)],t,vals[6][3]),t):
  k:=floor((1.-vals[4])*(n-1.));
  radi := unapply(spline([seq(i,i=0..k-2),k-.01,k,n-1],[seq(vals[3]*len,i=0..k-1),
    vals[5]*len,0],t,linear),t);
  plots[tubeplot]([x(t),y(t),z(t)],t=0..n-1,radius=radi(t),color=vals[2],gopts)
 else
  len := 0:
  for i from 2 to n do
   len := len+ evalf(sqrt(sum((vals[1][i][j]-vals[1][i-1][j])^2,j=1..di)))
  od:
  x :=  unapply(spline([seq(i,i=0..n-1)],
    [seq(vals[1][i][1],i=1..n)],t,vals[6][1]),t):
  y :=  unapply(spline([seq(i,i=0..n-1)],
    [seq(vals[1][i][2],i=1..n)],t,vals[6][2]),t):
  k:=floor((1.-vals[4])*(n-1.));
  band := NULL:
  z0 := x(0)+I*y(0):z1 := x(1./vals[7])+I*y(1./vals[7]);
  dir := evalf(evalc((z1-z0)/abs(z1-z0)));
  A := evalc(z0+I*vals[3]*dir): B := evalc(z0-I*vals[3]*dir):
  A := [Re(A),Im(A)]: B:= [Re(B),Im(B)]:
  for i from 2 to vals[7]*(k) do
   z0 := z1: z1 := x(i/vals[7])+I*y(i/vals[7]);
   dir := evalf(evalc((z1-z0)/abs(z1-z0)));
   C := evalc(z0+I*vals[3]*dir):
   d := evalc(z0-I*vals[3]*dir):
   C := [Re(C),Im(C)]:  
   d := [Re(d),Im(d)]:
   band := band,[A,B,d,C];
   A := C:
   B := d;
  od:
  for i from  k*vals[7]+1 to (n-1)*vals[7] do
   z0 := z1:
   z1 := x(1.*i/vals[7])+I*y(1.*i/vals[7]);
   dir := evalf(evalc((z1-z0)/abs(z1-z0)));
   C := evalc(z0+I*vals[5]*(n-1-i/vals[7])/(n-1-k)*dir):
   d := evalc(z0-I*vals[5]*(n-1-i/vals[7])/(n-1-k)*dir):
   C := [Re(C),Im(C)]:  
   d := [Re(d),Im(d)]:
   band := band,[A,B,d,C];
   A := C:
   B := d;
  od:
  plots[polygonplot]({band},color=vals[2]);
 fi;
end:
###end CARR

###DV
DV:=proc()
 local Args,ARGS,defaults,vals,len,tang,nor,plts,e1,e2;
 defaults:=tail=[0,0],head=[2,2],clr=black,name=``,angle=15,fudge=[0,0],Length=1,type="V";
 Args:=[tail,head,clr,name,angle,Length,fudge,type];
 ARGS:=PARAMS([defaults],[args]):
 vals := subs(ARGS[1],Args);
    
 len:= evalf(sqrt((vals[2][2]-vals[1][2])^2+(vals[2][1]-vals[1][1])^2));
 tang := (vals[2]-vals[1])/len:
 nor := [-tang[2],tang[1]]:
 e1 := evalf(vals[2] + vals[6]*(cos(Pi-vals[5]/180*Pi)*tang+sin(Pi-vals[5]/180*Pi)*nor));
 e2 := evalf(vals[2] + vals[6]*(cos(Pi+vals[5]/180*Pi)*tang+sin(Pi+vals[5]/180*Pi)*nor)):
 if vals[8]="V" then
  plts := DL(vals[1],vals[2],op(ARGS[2])),DL(vals[2],e1,
    op(ARGS[2])),DL(vals[2],e2,op(ARGS[2]))
 else
  plts := plottools[polygon]([vals[2],e1,e2],op(ARGS[2]))
 fi:
 if vals[4]<>`` then
  if type(vals[7],list) then
   plts:= plts,PT(vals[2]+vals[7],vals[4],op(ARGS[2]))
  else
   plts:= plts,PT((1+vals[7])*vals[2],vals[4],op(ARGS[2]))
  fi
 fi:
 plots[display](plts)
end:
###end DV

###PC
PC:=proc(Center,Radius)
 local Args,Thknss,Styl,Clr,Scalefactor,ARGS,defaults,PLOTOPTIONS:
 defaults:=radius=.1, thknss=2, styl=1, clr=black,scalefactor=1:
 Args:=seq([args][j],j=3..nargs):
 ARGS:=PARAMS([defaults],[Args]):
 PLOTOPTIONS:=op(PARAMS([defaults],[Args])[2]):
 Thknss:=subs(ARGS,thknss):
 Styl :=subs(ARGS,styl):
 Clr:=subs(ARGS,clr):
 Scalefactor:=subs(ARGS,scalefactor):
 plot([t->Center[1]+Radius*cos(t),t->Center[2]+Scalefactor*Radius*sin(t),0..2.*Pi],
  thickness=Thknss,linestyle=Styl,color=Clr,PLOTOPTIONS):
end:
###end PC

###roundto
roundto:=proc(x)
 local top, j, temp, n, ans, ARGS, defaults, Args, Places,
 Leadzero,lz;
 defaults := places = 3,leadzero=yes;
 Args := seq([args][j],j = 2 .. nargs);
 ARGS := PARAMS([defaults],[Args])[1];
 Places := subs(ARGS,places);
 Leadzero:= subs(ARGS,leadzero);
 temp := evalf(10^Places*x); top := convert(abs(round(temp)),symbol);
 n := length(top);
 if Leadzero=yes then lz := `0.` else lz:=`.` fi;
 if n = Places then ans:=cat(lz,seq(`0`,j = 1 .. Places-n),top);
 elif n < Places then ans := cat(lz,seq(`0`,j = 1 .. Places-n),top);
 else ans := cat(substring(top,1 .. length(top)-Places),`.`,substring(top,-Places .. -1))
 end if;
 if parse(ans) = .0 then ans := cat(lz,seq(`0`,j = 1 .. Places)) end if;
 #if evalf(x) < 0 then ans := cat(convert(StringTools[Char](6),symbol),ans) end if;
 if evalf(x) < 0 then ans := cat(`-`,ans) end if;
 #if LATEX_=yes then
convert(ans,string);
#else ans fi;
end proc:
###end roundto

##begin roundit
roundit:=proc (x)
local top, j, temp, n, ans,  defaults, opts, places, help,leadzero, commas,lz,writenum,ipart,dpart,strng;
defaults := Places = 2, Leadzero = yes,Commas=yes,Help=no,String=yes;
opts:=subs([op(select(type,[args],`=`)),defaults],[Help,Places,Leadzero,Commas,String]);
help:=convert(opts[1],string):
places:=opts[2]:
leadzero:=opts[3]:
commas:=opts[4]:
strng:=opts[5]:
if help="yes" then mcprint(
"roundit(x)  prints a number with commas and places set to 2.
options:
Help=no prints this screen
Places=2  set to the desired number of digits after the decimal
Leadzero=yes  set to no if no leading zero is printed before the decimal point for numbers lt 1
              set to nodecimal if the number is an integer and you don't want a decimal point.               
Commmas=yes  set to no if you don't want the integer part printed with commas.
String=yes   set to no if you want the number printed as a symbol.");
return(NULL) fi:
temp := evalf(10^places*x);
top := convert(abs(round(temp)),symbol);
n := length(top);
 writenum:=proc(n) local joe,bill,i,splitnum:
    splitnum:=proc(n) local tmp,joe,fillto;
   fillto:=proc(n,d) local len,tmp;
  if n=0 then RETURN(cat(seq(`0`,i=1..d))):fi:
  if length(n) >=d then RETURN(n)
  else tmp:=seq(`0`,i=1..(d-length(n)));fi:
 #print(length(n),d);
 #print(tmp,cat([tmp]));
  cat(tmp,`n`);end:
    if n<1000 then RETURN(n): fi:
    joe:=[]:
    tmp:=n:
    while tmp>1000 do:
    joe:=[fillto(irem(tmp,1000),3),op(joe)]:
 #print(joe,fillto(irem(tmp,1000),3)):
  tmp:=iquo(tmp,1000):
  od:
  joe:=[tmp,op(joe)]:end:
  if n<1000 then RETURN(n):fi:
  joe:=splitnum(n):
 #print(joe):
  bill:=joe[1]:
  for i from 2 to nops(joe) do:
  bill:=cat(bill,`,`,joe[i]):
 #print(bill):
  od:
  bill:end:
if leadzero = yes then lz := `0.` else lz := `.` end if;
if n = places then ans := cat(lz,seq(`0`,j = 1 .. places-n),top)
  elif n < places then ans := cat(lz,seq(`0`,j = 1 .. places-n),top)
elif commas=yes then
ipart :=writenum(parse(substring(top,1..length(top)-places)));
dpart:= substring(top,-places..-1);
ans := cat(ipart,`.`,dpart)
  else ans := cat(substring(top,1 .. length(top)-places),`.`,substring(top,-places .. -1))
end if;
if parse(ans) = 0. then ans := cat(lz,seq(`0`,j = 1 .. places))
 end if;
#print(ans);
if frac(x)=0. and leadzero=nodecimal then ans:=substring(ans,1..-2-places) fi;
if evalf(x) < 0 then ans := cat(`-`,ans)
end if;
if strng=yes then ans := convert(ans,string) fi:
ans;
end proc:
##end roundit
###hashang
hashang:=proc(A,B,C)
 local defaults,Args,bas,leg,basang,legang,joe,arcs,Radius,Numhashes,
       Headthickness,Headlength,Hashspacing,ARGS,PLOTOPTIONS,Arrowhead,ARROWHEAD,
       Withhead,Clr,Reversehead,Otherway,Fliphead:
 defaults:=radius=1,numhashes=3,hashspacing=.1,withhead=`NO`,headthickness=1,
       headlength=1,clr=black,reversehead=`NO`,otherway=`NO`,fliphead=`NO`:
 Args:=seq([args][j],j=4..nargs):
 ARGS:=PARAMS([defaults],[Args])[1]:
 PLOTOPTIONS:=op(PARAMS([defaults],[Args])[2]):
 Radius:=subs(ARGS,radius):
 Numhashes:=subs(ARGS,numhashes):
 Hashspacing:=subs(ARGS,hashspacing):
 Headthickness:=subs(ARGS,headthickness):
 Headlength:=subs(ARGS,headlength):
 Withhead:=subs(ARGS,withhead):
 Clr:=subs(ARGS,clr):
 Reversehead:=subs(ARGS,reversehead):
 Otherway:=subs(ARGS,otherway):
 Fliphead:=subs(ARGS,fliphead):
 bas:=expand(A-B);
 leg:=expand(C-B);
 basang:=evalf(arctan(bas[2],bas[1])):
 legang:=evalf(arctan(leg[2],leg[1])):
 if legang<basang then
  legang:=legang+2*Pi:
 fi:
 if basang<0 then
  basang:=basang+2*Pi:
  legang:=legang+2*Pi:
 fi:
 if Otherway<>`NO` then
  basang:=basang+2*Pi:
 fi:
 if Fliphead<>`NO` then
  Fliphead:=1
 else
  Fliphead:=-1:
 fi:
 #print(1.*basang,1.*legang);
 if (Withhead=`NO`) then
  arcs:=seq(  plot([B[1]+(Radius+j*Hashspacing)*cos(t),B[2]+
    (Radius+j*Hashspacing)*sin(t),
    t = legang..basang],thickness=1,color=black,PLOTOPTIONS),j=0..Numhashes-1);
  plots[display]([arcs]);
 elif  (Withhead<>`NO`) then
  if Reversehead=`NO` then
   Arrowhead:=[[B[1]+(Radius)*cos(basang),B[2]+(Radius)*sin(basang)],
      [B[1]+(Radius-.01*Headthickness)*cos(basang-.01*Fliphead*Headlength),
      B[2]+(Radius-.01*Headthickness)*sin(basang-.01*Fliphead*Headlength)],
      [B[1]+(Radius+.01*Headthickness)*cos(basang-.01*Fliphead*Headlength),
      B[2]+(Radius+.01*Headthickness)*sin(basang-.01*Fliphead*Headlength)]]:
   arcs:=plot([B[1]+(Radius)*cos(t),B[2]+(Radius)*sin(t),
      t = legang..basang],thickness=1,color=Clr,PLOTOPTIONS):
   ARROWHEAD:=plots[polygonplot](Arrowhead,color=Clr,style=patchnogrid,PLOTOPTIONS):
   plots[display]([ARROWHEAD,arcs]):
  elif Reversehead<>`NO` then
   Arrowhead:=[[B[1]+(Radius)*cos(legang),B[2]+(Radius)*sin(legang)],
     [B[1]+(Radius-.01*Headthickness)*cos(legang-.01*Fliphead*Headlength),
     B[2]+(Radius-.01*Headthickness)*sin(legang-.01*Fliphead*Headlength)],
     [B[1]+(Radius+.01*Headthickness)*cos(legang-.01*Fliphead*Headlength),
     B[2]+(Radius+.01*Headthickness)*sin(legang-.01*Fliphead*Headlength)]]:
   arcs:=plot([B[1]+(Radius)*cos(t),B[2]+(Radius)*sin(t),
     t = legang..basang],thickness=1,color=Clr,PLOTOPTIONS):
   ARROWHEAD:=plots[polygonplot](Arrowhead,color=Clr,style=patchnogrid,PLOTOPTIONS):
   plots[display]([ARROWHEAD,arcs]):
  fi:
 fi:
end:
###end hashang

###RANDANS
RANDANS:=proc(answers)
 local Answerstyle,ANSWERS,  ANS_TAG,ANS,answer,RNDANS,i,j,letters,defaults,Args,
       ARGS,Choices,Rightans,Ansform,NUMCHOICES,TMP_anstag,TMP_mcans,ANSWERCODE,k:
 ANSWERS:=[seq(convert(answers[i],string),i=1..nops(answers))]:
 letters:=["A","B","C","D","E","F","G","H","I","J","K","L","M"]:
 defaults:=rightans=1,choices=letters,answerstyle=mulchoice_labeled:
 Args:=seq([args][j],j=2..nargs):
 ARGS:=PARAMS([defaults],[Args])[1]:
 Choices:=subs(ARGS,choices):
 Rightans:=subs(ARGS,rightans):
 Answerstyle:=subs(ARGS,answerstyle):
 Choices:=[seq(Choices[i],i=1..nops(ANSWERS))]:
 NUMCHOICES:=nops(Choices):
 ANS := [seq((ANSWERS[i]),i = 1 .. nops(Choices))];
 if (nops([op({op(ANS)})]) < NUMCHOICES) then
  print("Warning: Duplicate Answer")
 fi;    
 RNDANS := combinat[randperm](ANS);
 TMP_anstag:=NULL:
 for i from 1 to NUMCHOICES-1 do
  TMP_anstag:=TMP_anstag,cat(RNDANS[1],";"):
 od:
 TMP_anstag:=cat(TMP_anstag,RNDANS[NUMCHOICES]):
 TMP_anstag:=seq(cat(RNDANS[i],";"),i=1..NUMCHOICES-1):
 TMP_anstag:=cat(TMP_anstag,RNDANS[NUMCHOICES]):
 TMP_mcans:="NULL":
 TMP_mcans:=cat(Choices[1],".   "),RNDANS[1]:
 for i from 2 to NUMCHOICES-1 do
  TMP_mcans:=TMP_mcans,cat(",   ",Choices[i],".   "),RNDANS[i]:
 od:
 TMP_mcans:=TMP_mcans,
 cat(",   ",Choices[NUMCHOICES],".   "),RNDANS[NUMCHOICES]:
 TMP_mcans:=cat(TMP_mcans):
 if Answerstyle=mulchoice_labeled then
  ANSWERCODE:=";":
  for i from 1 to nops(ANS) do
   if ( nops( [op({RNDANS[i],ANS[1]})])  =1) then
    ANSWERCODE:= cat(ANSWERCODE,Choices[i]):
    ANS_TAG:=NULL:
    for i from 1 to NUMCHOICES-1 do
     ANS_TAG:=cat(ANS_TAG,Choices[i],";")
    od:
    ANS_TAG:=cat(ANS_TAG,Choices[NUMCHOICES]):
    RETURN([ANSWERCODE,ANS_TAG,TMP_mcans]):
   fi:
  od:
 fi:
 if Answerstyle<>mulchoice_labeled then
  if (Answerstyle=AB) then
   ANSWERCODE:=NULL:
   for i to NUMCHOICES do
    ANSWERCODE:=cat(ANSWERCODE,";"):
    for k from 1 to Rightans do
     if ( nops( [op({RNDANS[i],ANS[k]})])  =1)   then
      ANSWERCODE:= cat(ANSWERCODE,RNDANS[i])
     fi:
    od:
   od:
  else
   ANSWERCODE:=cat(";",ANS[1]):
  fi:
  RETURN([ANSWERCODE,cat(TMP_anstag)]);
 fi:
end:
###end RANDANS

###fill
fill :=proc(f,g,a,b)
 local n,ps,pl1,pl2,pl3,c1,c2,c3,i,vals,defaults,Args,ARGS,p,m,approx,h;
 h := abs@(f-g);
 defaults:=Color=[yellow,black,black],Numpts=49,partition=regular,rule=left,
 Style=patchnogrid,Thickness=[1,1];
 Args:=[Color,Numpts,partition,rule,Style,Thickness,marks];
 ARGS:=PARAMS([defaults],select(type,[args],equation)):
 vals := subs(ARGS[1],Args);
 if nops(vals[1])=3 then
  c1:=vals[1][1]:
  c2:=vals[1][2]:
  c3:=vals[1][3]
 else
  c1 := vals[1]:
  c2:=vals[1]:
  c3:=vals[1]
 fi:
 n := vals[2]:
 if convert(vals[3],string)="regular" then
  p := [seq(a+i*(b-a)/n,i=0..n)]
 else
  p := [a,op(vals[3]),b];
  n := nops(p)-1
 fi;
           
 if convert(vals[4],string)="left" then
  m := [seq(p[i],i=1..n)]
 elif convert(vals[4],string)="right" then
  m := [seq(p[i+1],i=1..n)]
 elif convert(vals[4],string)="mid" then
  m := [seq((p[i]+p[i+1])/2,i=1..n)]
 elif convert(vals[4],string)="trap" then
  m := p  
 else  
  if nops(vals[7]) <> n then
   ERROR("Need ",n," marks.")
  fi:
  m := vals[7]
 fi;
 pl1 :=plot([f,g],a..b,color=[c2,c3],thickness=vals[6]);
 if convert(vals[4],string)="trap" then
  pl2 := plots[display]([seq(plots[polygonplot]([
     [p[i],f(p[i])],[p[i],g(p[i])],[p[i+1],g(p[i+1])],[p[i+1],f(p[i+1])]],
     color=c1,style=vals[5]),i=1..n)]) ;
  approx := sum((h(p[i])+h(p[i+1]))/2*(p[i+1]-p[i]),i=1..n);
 else
  pl2 := plots[display]([seq(plots[polygonplot]([
     [p[i],f(m[i])],[p[i],g(m[i])],[p[i+1],g(m[i])],[p[i+1],f(m[i])]],
     color=c1,style=vals[5]),i=1..n)]);
  approx := sum(h(m[i])*(p[i+1]-p[i]),i=1..n)
 fi;
 plots[display](pl1,pl2,op(ARGS[2])),approx;
end:
###end fill

###Axes
Axes:= proc()
 local Args,ARGS,defaults,vals,pl1,pl2,x,y;
 defaults:=xrng=[-5,10],yrng=[-5,10],clrs=[blue,blue],thkns=2,head=[.5,.2];  
 Args:=[xrng,yrng,clrs,thkns,head];
 ARGS:=PARAMS([defaults],[args]):
 vals := subs(ARGS[1],Args);
 x := vals[1]: y := vals[2]:
 pl1:=plot({[[x[1],0],[x[2],0]],
   [[x[2]-vals[5][1],vals[5][2]],[x[2],0],[x[2]-vals[5][1],
   -vals[5][2]]]},color=vals[3][1],thickness=vals[4]);
 pl2:=plot({[[0,y[1]],[0,y[2]]],
   [[vals[5][2],y[2]-vals[5][1]],[0,y[2]],[-vals[5][2],y[2]-vals[5][1]]]},
   color=vals[3][2],thickness=vals[4]);
 plots[display](pl1,pl2,view=[x[1]..x[2],y[1]..y[2]])
end:
###end Axes

###Header
Header := proc(n)
 if member(n,{0,1,2,3})  then
  mcprint("AH_[",n,"]")
 else
  mcprint("AH_")
 fi:
 NULL
end:
###end Header

###ah_
ah_ := proc()
 local n;
 if nargs > 0 then
  n:= args[1];
  if member(n,{0,1,2,3,4}) then
   cat("\nAH_[",n,"]")
  else
   cat("\nAH_[0]")
  fi
 else
  cat("\nAH_[0]")
 fi:
end:
###end ah_

###av_
av_ := proc()
 local file,message,n,bill;
 if nargs = 3 and type(args[1],integer) and
    type(args[2],string) and type(args[3],string) then
  n := args[1]:
  file := args[2]:
  message := args[3]:
 elif nargs  = 2 and type(args[1],string) and type(args[2],string) then
  n := 3:
  file := args[1]:
  message := args[2]
 elif nargs  = 2 and type(args[1],integer) and type(args[2],string) then
  n := args[1]:
  file := args[2]:
  message := "Press"
 elif nargs  = 1 and type(args[1],string) then
  n := 3:
  message := "Press":
  file := args[1]
 else
  ERROR("check av_ arguments")
 fi;
 cat("\nAH_[",n mod 4,";",file,";",message,"]\n")
end:
###end av_

`&=` := proc(a,b)
    if nops([a,b])=2 then
      if type(b,set) or type(b,list) then
  assign(a,b[rand(1..nops(b))()])
  elif type(b,`..`)  then
  assign(a,rand(b)())
  elif type(b,integer) and  nargs=3 then
     assign(a,evalf(1/10^(b)*rand(args[3])(),b+1))  
  elif type(b,procedure) then
     assign(a,b())
  else
  assign(a,b)
  fi;
  fi;
  end:

 `&==` := proc(a,b)     
   local c:         
   if not type(a,symbol) then error "The left operand of &== must be a symbol." fi:
   if type(b,set) or type(b,list) then
    assign(a,()->b[rand(1..nops(b))()]):
   elif type(b,`..`)  then
    assign(a,rand(b));
   elif type(b,integer) and  nargs=3 then
     c := args[3]:
     assign(a,()->(.1)^(b)*rand(eval(c))())
   elif type(b,procedure) then
     assign(a,b)
   else  
    assign(a,()->b)
   fi;
   op(1,a);
  end:
  

>    assignvals := proc()
  local Args,lst,defaults,opts,help,i,fun;
defaults:=Help=no,Function=no;
opts:=  selectremove(type,[args],`=`);
Args:=opts[2]:
opts:=subs([op(opts[1]),defaults],[Help,Function]):
help := opts[1]: fun:= opts[2]:
 if help=yes then
 mcprint("assignvals(exprseq)  takes a exprseq of ['X',range] or ['X',d,m..n] or ['X',perm,list]
 or ['X',mat,list] or ['X',struct,command],and assigns X a random value chosen thusly:
 1. for ['X',range] X is assigned a value in range, where range can be an integer range  m..n,
or a set or list of values
 2. for ['X',d,m..n] d is a positive integer, m..n is an integer range and X is assigned a random floating  point with d significant digits between  m/10^d and n/10^d.
 3. for ['X',perm,list]  X is assigned a random permuation of the elements in the list.
 4. for ['X',list,listofvalues]  X is assigned the listofvalues
 5. for ['X',mat,list]  X is assigned a random list of lists using list as the argument to LinearAlgebra[RandomMatrix].   
Example: ['c',mat,[2,3,generator=rand(1..4),density=.8]] assigns c a
   2 by 3 list of lists of 20% zeros, 80% random numbers between 1 and 4.
 6. for ['X',struct,command] X is assigned the output of the maple command.
Example:  ['b',struct,plot(x^2,x=0..4)] assigns b the plot structure for the graph of x^2.
  
Note 1: no variable can depend on a variable assigned in that call to assignvals.  
 Example:
 illegal  assignvals(['A',[2,3,4,5]],['B',[\"t\",b,c,1]],['C',[A,A,A,B]]);
 legal    assignvals(['A',[2,3,4,5]],['B',[\"t\",b,c,1]]): assignvals(['C',[A,A,A,B]]);
Note 2: assignvals is written to work with paramvals (aka getparams).  In cases where parameters are to be
assigned values which depend on previously assigned values such as the legal example above, you would make
a call to paramvals after using assignvals, like so:
 assignvals(['A',[2,3,4,5]],['B',{\"t\",b,c,1}]):
 assignvals(['C',[A,A,A,B]]);
 getparams([args],[['A',[A]],['B',[B]],['C',[C]]]);
  
 Options:  
 Help=no  change to yes to get this message."):
 RETURN(NULL) fi:
 for i from 1 to nops(Args) do
 if nops(Args[i])=3 and StringTools[LowerCase](StringTools[SubString](convert(Args[i][2],string),1..6))="struct" then assign(Args[i][1],Args[i][3])
elif nops(Args[i])=3 and StringTools[LowerCase](StringTools[SubString](convert(Args[i][2],string),1..3))="mat" then assign(Args[i][1],convert(LinearAlgebra[RandomMatrix](op(Args[i][3])),listlist))
elif nops(Args[i])=3 and StringTools[LowerCase](StringTools[SubString](convert(Args[i][2],string),1..4))="list" then assign(Args[i][1],Args[i][3])
elif nops(Args[i])=3 and StringTools[LowerCase](StringTools[SubString](convert(Args[i][2],string),1..4))="perm" then assign(Args[i][1],combinat[randperm](Args[i][3]))
  else
 if nops(Args[i])=2 then
Args[i][1] &= Args[i][2];  
else  Args[i][1] &= (Args[i][2],(Args[i][3])) fi
 fi:
od: return NULL:
     end:

paramvals := proc()
local ar,ls1,ar2,i,par,pcname;
if nargs=1 then ar:=args[1]: fi;
if nargs>1 then ar:=(args[1]):ls1:=args[2];
    if nops(ls1)>1 then ar := ListTools[FlattenOnce](ar) fi fi;
if nargs=3 then pcname:= args[3] else pcname:=" " fi;

if nops(ar)=0 then error "Need a problem number." fi:
if nops(ar)=0 or StringTools[Search]("help",convert(args[1],string))>0 or
StringTools[Search]("Help",convert(args[1],string))>0 then
mcprint("paramvals([args],ls1) where  args is the sequence of arguments to the problem generator,
and ls1 is a list of lists of parameter names
and range specifications suitable for assignvals (See assignvals(Help=yes) below).
Note: this was written to be used in a problem generator.
Usually, you will call something like paramvals([args],[[a,{2,3,1}],...])
Then when the generator is called with just a version number, the list which is printed
can be pasted back into the call to get the same inputs in case maintainance is needed.");
mcprint("\n Help for assignvals ");assignvals(Help=yes); return NULL fi:
par :=["parameter list: ",seq(op([ls1[i][1],","]),i=1..nops(ls1)-1),ls1[nops(ls1)][1]];
 
if nops(ar)>1 then ls1:=(ls1):
 if nops(ar)=nops(ls1)+1 then
ar2 := NULL: for i from 2 to nops(ar) do  if type(ar[i],list) then ar2:= ar2,[ar[i]] else ar2:=ar2,ar[i] fi od;
assignvals(seq([ls1[i][1],ar2[i]],i=1..nops(ls1)))
else
error "Need a problem number and values for each parameter or no parameter." fi fi;
if nops(ar)=1 then
assignvals(op(ls1))
fi;
mcprint("current inputs are ",pcname,"(",ar[1],",[",seq(op([eval(ls1[i][1]),","]),
i=1..nops(ls1)-1),eval(ls1[nops(ls1)][1]),"])");
end:

getparams := proc(ar,ls1)
local ar2,i,par,pcname;
if nargs=3 then pcname:= args[3] else pcname:=" " fi;
#if nops([args])=2 then ar:=arg[1]; ls1:= arg[2]; else error "need two arguments. Try getparams(Help=yes)." #fi;
if nops(ar)=0 then error "Need a problem number." fi:
if StringTools[Search]("help",convert(ar[1],string))>0 or
StringTools[Search]("Help",convert(ar[1],string))>0 then
mcprint("getparams is superceded by. Use paramvals instead."); return NULL fi:
par :=
["parameter list: ",seq(op([ls1[i][1],","]),
i=1..nops(ls1)-1),ls1[nops(ls1)][1]];
 
if nops(ar)>1 then if nops(ar)=nops(ls1)+1 then
ar2 := NULL: for i from 2 to nops(ar) do  if type(ar[i],list) then ar2:= ar2,[ar[i]] else ar2:=ar2,ar[i] fi od;
assignvals(seq([ls1[i][1],ar2[i]],i=1..nops(ls1)))
#assignvals(seq([ls1[i][1],ar[i+1]],i=1..nops(ls1)))
else
error "Need a problem number and values for each parameter or no parameter." fi fi;
if nops(ar)=1 then
assignvals(op(ls1))
fi;
mcprint("current inputs are ",pcname,"(",ar[1],",",seq(op([eval(ls1[i][1]),","]),
i=1..nops(ls1)-1),eval(ls1[nops(ls1)][1]),")");
#mcprint(op(par));
end:


>   
###generator
generator := proc()
 global QMline,probline,HARDCOPY_,BOXLENGTH_,ERROR_,PNUM_,RNGCHK;
 local vals,ARGS,Args,defaults,p,ansline,i,j,ij,k,atype,line,subline,sp,nm,
       M,r,c,ah,e,err,anstypes,L,S,cc,ce,A,B,C,D,E,F,G,jack,vars,AARGs,ags,
       ch,g,pnum,ans,ant,mij,va,rngck;
rngck:=cat(convert(RNGCHK_[1],string),";",convert(RNGCHK_[2],string));
 ah := table([]);
 ah["0_"]:=0;ah["1_"]:=1;ah["2_"]:=2;ah["3_"]:=3;
 defaults:=brks=0,hidden=no,pretext=none,
 problem=[["What  is 2 + 3?"],plots[display]([plottools[disk]([0,0],4,color=yellow),
  PT([0,0],"2 + 3 = ?",clr=magenta,fontsize=24,font=[HELVETICA,24],axes=none)]),
  matrix([[`two plus three equals     what`]]),["There is only one answer."]],
  aftertext=[[""]],
 answers=[3,10,9,5],
 rightanswers=5,
 ansmat=matrix([[1,2]]),
 incidmat=matrix([[1,0]]),
 Alabels=[A,B,C,D,E,F,G,H],
 anstype=radio,
 call=only,
 txtboxsize=BOXLENGTH_,
 precision=ERROR_,
 funstuff="3;x;y;z;5;0;1;2;3;-1;2",
 randomize=yes,
 matsize=[1,5],
 cellcolor=white,
 tableoptions="border=\"0\"",
 Flabels="red",
 inline=no,
 video=[""],
 expressioncheck=[15,5,1,2],
 standards="";

 Args:=[problem,answers,brks,rightanswers,Alabels,
   anstype,pretext,call,hidden,txtboxsize,
   precision,ansmat,incidmat,funstuff,randomize,
   aftertext,matsize,cellcolor,tableoptions,Flabels,
   inline,video,expressioncheck,standards];

 AARGs := [answerheader=brks,audio=video,introduction=pretext,statement=problem,
   matrixsize=matsize,showthese=incidmat,answerformat=anstype, rightanswer=rightanswers,
   accuracy=precision,boxsize=txtboxsize,oneline=inline];

 ags := NULL:
 for e in [args] do
  ch := 0;
  for g in AARGs do
   if lhs(e)=lhs(g) then
    ags := ags,rhs(g)=rhs(e);
    ch:=1
   fi
  od;
  if ch=0 then
   ags:=ags,e
  fi;
 od;

 for e in [ags] do
  if not member(lhs(e),{op(Args)}) then
   ERROR("The option ",lhs(e)," is not in the list of options -- check spelling.
     Current options:",Args);   
  fi
 od;

 ARGS:=PARAMS([defaults],[ags]):
 vals := subs(ARGS[1],Args);
 if STANDARDS_<>yes then vals[24]:="" fi;
 anstypes:=[numberbox,numericbox,textbox,wordbox,complex,ungraded,userdefined,tablebox,
    spreadbox,functionbox,integralbox,mfunctionbox,crossword,radio,vradio,sradio,selection,
    checkbox,zbox,qbox,radiolabelled,radiospread,radiospreadvert,radiospreadhorz,checkboxlabelled,
    checkboxspread,checkboxspreadvert,checkboxspreadhorz,expression];
 if not member(vals[6],{op(anstypes)}) then
  err:="The anstype ",vals[6]," is not in the list of answer types -- check spelling.
    Current answer types:",anstypes;  
  ERROR(err)
 fi ;

 if (vals[6]=textbox or vals[6]=numberbox) and not (type(vals[4],string) or
    type(vals[4],list)) and not type(evalf(vals[4]),float) then  
  ERROR("This answer format does not accept expression with variables.
   The supplied answer is:",vals[4])
 fi:

 if member(vals[6],{selection,radio,vradio,radiolabelled})
    and not type(vals[2],list) then
  ERROR("This answer format requires a list of possible answers, with correct answer
    listed first.")
 fi;

 if nops(vals[21])=1 and convert(vals[21],string)="yes" then
  vals[1]:=[lineit(vals[1])]
 fi;
 if nops(vals[21])=1 and convert(vals[21],string)="yes, including answer." then    vals[1]:=[lineit(vals[1],endtable=no)];
  vals[16]:=[lineit(vals[16],startable=no,endtable=yes)]
 fi;
 if nops(vals[21])>1 then  
  vals[1]:=[lineit(vals[1],endtable=no)];
  vals[16]:=[lineit(vals[16],startable=no,endtable=yes)]  
 fi;
      
 if nops({op(vals[2][1..-1])}) < nops(vals[2][1..-1]) then
  print(vals[2][1..-1]);
  ERROR("duplicate answers.")
 fi;

 if vals[15]=yes then
  p := combinat[randperm]([seq(i,i=1..nops(vals[2]))])
 else
  p := [seq(i,i=1..nops(vals[2]))]
 fi;  

 if member(vals[8],{first,only}) then
  QMline:= NULL
 fi;

#if member(vals[6],{numericbox,textbox,numberbox}) then
#  if not type(vals[4],list) then #chkp(parse(convert(vals[4],string)),parse(convert(vals[11],string))) #fi;
#fi;
 
if vals[6]=numericbox then   
  ansline:="AN_[",convert(vals[10],string);
  if member(vals[3],{1,3,after,beforeafter}) then
   ansline := ansline,"]\n"
  else
   ansline := ansline,"]"
  fi;
  if type(vals[4],list) then
   vals[4] := StringTools[Join](map(convert,vals[4],string),",")
  fi;
  QMline:=QMline,";",convert(vals[4],string);
 fi;
####AZstuff
if vals[6]=zbox then
  ansline:="AZ_[",vals[4][1],"]\n";
  QMline:=QMline,";",vals[4][2];
fi;
 if vals[6]=textbox or vals[6]=numberbox then

   
  ansline:="AC_[",convert(vals[10],string);
  if member(vals[3],{1,3,after,beforeafter}) then
   ansline := ansline,"]\n"
  else
   ansline := ansline,"]"
  fi;
  if type(vals[4],list) then
   vals[4] := StringTools[Join](map(convert,vals[4],string),",")
  fi;
  QMline:=QMline,";",convert(vals[4],string);
 fi;

 if vals[6]=complex then
  ansline:="AC_[",convert(vals[10],string),"]\n + i\nAC_[",convert(vals[10],string);
  if member(vals[3],{1,3,beforeafter,after}) then
   ansline := ansline,"]\n"
  else
   ansline := ansline,"]"
  fi;
  QMline:=QMline,";",convert(Re(vals[4]),string),";",convert(Im(vals[4]),string)
 fi;

 if vals[6]=wordbox then  
  ansline:="AW_[",convert(vals[10],string);
  if member(vals[3],{1,3,beforeafter,after}) then
   ansline := ansline,"]\n"
  else
   ansline := ansline,"]"
  fi;
  QMline:=QMline,";",convert(vals[4],string);
 fi;

 if vals[6]=ungraded then
  if vals[8] <> only then
   mcprint("Warning: questions with ungraded parts are all ungraded.")
  fi;
  ansline:="AX_[",convert(vals[10],string),"]\n";
  QMline:=QMline,";Your answer will be hand graded.";
 fi;

 if vals[6]=userdefined then
  ansline:=vals[2];  
  QMline:= QMline,vals[4]
 fi;

 if vals[6] = tablebox or vals[6]=spreadbox  then
  M := (vals[12]);
  r := linalg[rowdim](M);
  c := linalg[coldim](M);
  if linalg[rowdim](vals[13])<>r or linalg[coldim](vals[13])<>c then            
   ERROR(print(ansmat=vals[12],incidmat=vals[13]),  
      "The dimensions of ansmat and incidmat are unequal")
  fi;
  if not vals[6]=crossword then
   ansline:="AT_[",vals[10],";",r,";",c;
   for i from 1 to r do for j from 1 to c do
    if vals[13][i,j]=1 then
     QMline := QMline,";",M[i,j] ;
     if vals[6]=tablebox then
      M[i,j]:=NULL
     else
      M[i,j] := AC_[vals[10]]
     fi  
    fi;
    ansline:=ansline,";",M[i,j];
   od
  od;
  ansline:=ansline,"]\n";
 else
  ####crossword###
  ansline:=["lt_table",vals[19],"gt_"];
  for i from 1 to r do
   ansline:=ansline,["lt_tr gt_"];
   for j from 1 to c do
    cc := vals[18]:
    if vals[13][i,j]=1  and member(nops(M[i,j]),{3,4}) then
     
     if nops(M[i,j])=4 then  
      cc := M[i,j][4];
     fi:
     ansline:=ansline,["lt_td bgcolor=\"",cc,"\"gt_\nA",
       M[i,j][1],"_[",M[i,j][2],"]\n"];
     QMline:=QMline,";",M[i,j][3];
    elif member(nops(M[i,j]),{1,2}) then
     ce := M[i,j][1]:
     if nops(M[i,j])=2 then
      cc := M[i,j][2]:
     fi:
     if type(M[i,j][1],string) then
      ce:= [M[i,j][1]]
     fi;
     ansline:= ansline,["lt_td bgcolor=\"",cc,"\"gt_"], ce  
    else
     ERROR("Cell ",[i,j]," has an error.")
    fi;
    ansline:=ansline,["lt_/td gt_"];
   od;  
   ansline:=ansline,["lt_/tr gt_"];
  od;
  ansline:=ansline,["lt_/table gt_"];    
 fi;
fi;

if  vals[6]=crossword then
 M := (vals[12]);
 r := linalg[rowdim](M);
 c := linalg[coldim](M);
 
 ansline:=["lt_table ",vals[19]," gt_"];
 for i from 1 to r do
  ansline:=ansline,["lt_tr gt_"];
  for j from 1 to c do
   cc := vals[18]:   ce := vals[10]:
   if not type(M[i,j],list) then
    mij := [M[i,j]]
   else
    mij:=M[i,j]
   fi:
  
   if nops(mij)=1 then
    ce := M[i,j];
    ansline := ansline,["lt_td bgcolor=\"",cc,"\" gt_"],ce
   elif nops(mij)>1 and  member(convert(M[i,j][1],string),{"C","W","S","E","F"}) then
    ant := convert(M[i,j][1],string);
    if ant = "C" then
     ans := M[i,j][2];#chkp(ans);
    elif ant = "E" then
     ans := M[i,j][2];#chkf(ans);
     va := select(type,indets(M[i,j][2]),symbol);
     ce := cat(vals[10],";",nops(va),seq(cat(";",va[k]),k=1..nops(va)));
     if nops(mij)=3 then
      ce := cat(ce,";",M[i,j][3])
     else
      #rngck
      #ce := cat(ce,";6",seq(";.1;1",k=1..nops(va)))
      ce := cat(ce,";6",seq(cat(";",rngck),k=1..nops(va)))
     fi;
    elif ant = "W"  then
     if type(M[i,j][2],list) then
      ans := cat(convert(M[i,j][2][1],string),seq(cat("#",convert(M[i,j][2][k],string)),
        k=2..nops(M[i,j][2]))) else
      ans := M[i,j][2]
     fi
    elif ant = "F" then
     #print(M[i,j]);
     if nops(M[i,j])>2 and type(M[i,j][3],list) then
      ans:=M[i,j][2]:
ce:=cat(vals[10],";",StringTools[Join](map(convert,M[i,j][3],string),";"));
     else

       ans := M[i,j][2];#chkf(ans);
     ce := cat(vals[10],";",convert(op(select(type,indets(M[i,j][2]),symbol)),string));
     if nops(mij)=3 then
      ce := cat(ce,";",M[i,j][3])
     else
      #rngck
      ce := cat(ce,";6;",rngck)
     fi;
    fi;                
    elif ant = "S" then
     if vals[15]=yes then
      p := combinat[randperm]([seq(i,i=1..nops(M[i,j][2]))])
     else
      p := [seq(i,i=1..nops(M[i,j][2]))]
     fi;
     ans := M[i,j][2][1]:
     ce := cat(convert(M[i,j][2][p[1]],string),seq(cat(";",
       convert(M[i,j][2][p[k]],string)),k=2..nops(M[i,j][2])))
    fi;
    if nops(mij)=3 and not type(M[i,j][3],list) then
      cc := M[i,j][3];  
     fi;
     ansline:=ansline,["lt_td bgcolor=\"",cc,"\"gt_\nA",ant,"_[",ce,"]\n"];
     #ansline:=ansline,["lt_td bgcolor=",cc,"gt_\nA",ant,"_[",ce,"]\n"];
     QMline:=QMline,";",ans;
    else
     if nops(mij)=2 then
      ce := M[i,j][1]:
      cc := M[i,j][2]
     fi:
     #ansline:= ansline,["lt_td bgcolor=",cc," gt_"],ce
     ansline:= ansline,["lt_td bgcolor=\"",cc,"\"gt_"],ce
    fi;
    ansline:=ansline,["lt_/td gt_"];
   od;  
   ansline:=ansline,["lt_/tr gt_"];
  od;
  ansline:=ansline,["lt_/table gt_"];    
 fi;
#rngck
 if vals[6]=functionbox then #chkf(vals[4]);  
   QMline := QMline,";",vals[4];      
  ansline:="AF_[",vals[10],";",vals[14][1],";",vals[14][2],";",
     vals[14][3],";",vals[14][4];
  if member(vals[3],{1,3,beforeafter,after}) then
   ansline := ansline,"]\n"
  else
   ansline := ansline,"]"
  fi;
 fi;

 if vals[6]=integralbox then #chkf(vals[4]);
  QMline := QMline,";",vals[4];  
  ansline:="AI_[",vals[10],";",vals[14][1],";",vals[14][2],";",
    vals[14][3],";",vals[14][4];
  if member(vals[3],{1,3,beforeafter,after}) then
   ansline := ansline,"]\n"
  else
   ansline := ansline,"]"
  fi;
 fi;

 if vals[6]=mfunctionbox then
   QMline := QMline,";",vals[4];  
  ansline:="AE_[",vals[10],";",vals[14];
  if member(vals[3],{2,3}) then
   ansline := ansline,"]\n"
  else
   ansline := ansline,"]"
  fi;
 fi;

 if vals[6]=expression then
  QMline := QMline,";",vals[4];
  vars :=[op(indets(vals[4]),symbol)];
  vars:=cat(vals[23][1],";",nops(vars),";",seq(cat(vars[i],";"),
   i=1..nops(vars)),vals[23][2],seq(cat(";",vals[23][3],";",
   vals[23][4]),i=1..nops(vars)));  
  ansline:="AE_[",vars;
  if member(vals[3],{1,3,beforeafter,after}) then
   ansline := ansline,"]\n"
  else
   ansline := ansline,"]"
  fi;
 fi;

 if vals[6]=vradio then
  pnum := rand();
  ansline:=NULL:
  for i from 1 to nops(vals[2]) do
   ansline := ansline,"AR","_[",pnum,"]\n",convert(vals[2][p[i]],string),"\n\n"
  od:
  for i from 1 to nops(vals[2]) do
   if p[i]=1 then
    pnum:=i
   fi
  od:
  QMline:=QMline,";",convert(pnum,string)
 fi;

 if vals[6]=qbox then
  if not type(vals[2],list) then  
     ansline := cat("AQ","_[",convert(vals[2],string),";1]");
   QMline:=QMline,";"
  else ansline := cat("AQ","_[",convert(vals[2][1],string),";1]");
   QMline:=QMline,convert(vals[2][2],string)
   fi
 fi;


 if vals[6]=sradio then
  if not type(vals[2],list) then  
     ansline := cat("AR","_[",convert(vals[2],string),";1]")
  else ansline := cat("AR","_[",convert(vals[2][1],string),";1]");
   QMline:=QMline,";",convert(vals[2][2],string)
   fi
 fi;

 if member(vals[6],{checkboxspread,radio,selection,checkbox,      radiospread,checkboxspreadvert,checkboxspreadhorz,
  radiospreadvert,radiospreadhorz}) then
  if type(vals[4],list) then
   if nops(vals[4]) <> nops(vals[2]) then     
     ERROR(mcprint(answers=vals[2],"\n",rightanswers=vals[4]),
      "the list of rightanswers must be the same length as the list of answers")
   fi
  fi
 fi;

 if member(vals[6],{radiospread,checkboxspread,radiolabelled,checkboxlabelled}) and
    nops(vals[5])<nops(vals[2]) then
  ERROR("Need more labels")
 fi;

 if vals[6]=radio or vals[6]=selection then
  if vals[6]=radio then
   atype := L
  else
   atype:=S
  fi;
  ansline:="A",atype,"_[",convert(vals[2][p[1]],string);
  for i from 2 to nops(vals[2]) do
   ansline:= ansline,";",convert(vals[2][p[i]],string)
  od:
  ansline:=ansline,"]";
  if member(vals[3],{1,3}) or atype=L then
   ansline:=ansline,"\n"
  fi;
  if type(vals[4],list) then
   for i from 1 to nops(vals[4]) do
    if vals[4][p[i]]=1 then
     QMline:=QMline,";",convert(vals[2][p[i]],string)
    fi
   od
  else
   QMline:=QMline,";",convert(vals[4],string)
  fi;  
 fi;

 if vals[6]=checkbox then atype:=B;
      ansline:="A",atype,"_[",convert(vals[2][p[1]],string);
  if vals[4][p[1]]=1 then
   QMline:=QMline,";",convert(vals[2][p[1]],string)  
  else
   QMline:=QMline,";"
  fi;
  for i from 2 to nops(vals[2]) do
   ansline:= ansline,";",convert(vals[2][p[i]],string);
   if vals[4][p[i]]=1 then
    QMline:=QMline,";",convert(vals[2][p[i]],string)  
   else
    QMline:=QMline,";"
   fi;
  od;
  ansline:=ansline,"]\n";
 fi;
 ## kemtpformat
 if vals[6]=radiolabelled or vals[6]=checkboxlabelled then
  if vals[6]=radiolabelled then
   atype:=L
  else
   atype:=B
  fi;
  sp := "  spc_  ":  
  line :=["lt_table gt_lt_tr gt_lt_td valign=\"middle\" gt_ lt_font color=\"",
    vals[20],"\" gt_ lt_b gt_",vals[5][1],". lt_/b gt_ amp_nbsp; lt_/font gt_lt_/td gt_"],
    ["lt_td valign=\"middle\" gt_"], vals[2][p[1]], [" lt_/td gt_"];   
  ansline:="A",atype,"_[",convert(vals[5][1],string);
  for i from 2 to nops(vals[2]) do
   ansline:= ansline,";",convert(vals[5][i],string);
   if iquo(i,vals[17][2])>0 and (irem(i,vals[17][2])=1 or (vals[17][2] =1
      and i <= nops(vals[2]))) then
    line:=line,["lt_/tr gt_lt_tr gt_"],
     ["lt_td valign=\"middle\" gt_lt_font color=\"", vals[20] ,
     "\" gt_lt_b gt_",vals[5][i],
     ". lt_/b gt_ amp_nbsp; lt_/font gt_lt_/td gt_"],
     ["lt_td valign=\"middle\" gt_"], vals[2][p[i]],["lt_/td gt_"]  
   else
    line:= line,
      ["lt_td valign=\"middle\" gt_lt_font color=\"", vals[20] ,
      "\" gt_lt_b gt_ amp_nbsp; ",vals[5][i],
      ". lt_/b gt_ amp_nbsp; lt_/font gt_lt_/td gt_"],
      ["lt_td valign=\"middle\" gt_"], vals[2][p[i]],["lt_/td gt_"]
   fi:
  od:

  line := line,["lt_/tr gt_lt_/table gt_"];
  ansline := line,["\n"],[ansline,"]\n"];

  if vals[6]=checkboxlabelled then
   if vals[4][p[1]]=1 then
    QMline:=QMline,";",convert(vals[5][1],string)  
   else QMline:=QMline,";" fi;
    for i from 2 to nops(vals[2]) do
     if vals[4][p[i]]=1 then
      QMline:=QMline,";",convert(vals[5][i],string)  
     else
      QMline:=QMline,";"
     fi  
    od
   else
    if type(vals[4],list) then
     for i from 1 to nops(vals[4]) do
      if vals[4][p[i]]=1 then
       QMline:=QMline,";",convert(vals[5][i],string)
      fi
     od
    else
     for i from 1 to nops(vals[2]) do
      if convert(vals[4],string)=convert(vals[2][p[i]],string) then        
       QMline:=QMline,";",convert(vals[5][i],string)
      fi;
     od  
    fi
   fi
  fi;

  if vals[6]=radiospreadvert or vals[6] = radiospreadhorz then
   atype:=L;
   line:=NULL;
   if type(vals[4],list) then
    for i from 1 to nops(vals[4]) do
     if vals[4][p[i]]=1 then
      QMline:=QMline,";",convert(vals[5][i],string)
     fi
    od
   else
    for i from 1 to nops(vals[2]) do
     if convert(vals[4],string)=convert(vals[2][p[i]],string) then       
      QMline:=QMline,";",convert(vals[5][i],string)
     fi;
    od  
   fi;
   if vals[6]=radiospreadvert then
    line:= [convert(cat(vals[5][1],"."),symbol),vals[2][p[1]]]  
   else
    line := convert(cat(vals[5][1],"."),symbol),vals[2][p[1]]
   fi;                
   ansline:="A",atype,"_[",convert(vals[5][1],string);
   for i from 2 to nops(vals[2]) do
    ansline:= ansline,";",convert(vals[5][i],string);
    if vals[6]=radiospreadvert then
     line:= line,[convert(cat(vals[5][i],"."),symbol),vals[2][p[i]]]    
    else
     line := line, convert(cat(vals[5][i],"."),symbol),vals[2][p[i]]
    fi;
   od:
   ansline:=ansline,"]\n";  
  fi;
  if vals[6]=checkboxspreadvert or vals[6]=checkboxspreadhorz then
   atype:=B;
   sp := "  spc_  ":  
   if vals[6]=checkboxspreadvert then
    line:= [convert(cat(vals[5][1],".   "),symbol),vals[2][p[1]]]  
   else
    line := convert(cat(vals[5][1],".   "),symbol),vals[2][p[1]]
   fi;               
   ansline:="A",atype,"_[",convert(vals[5][1],string);
   if vals[4][p[1]]=1 then
    QMline:=QMline,";",convert(vals[5][1],string)  
   else
    QMline:=QMline,";"
   fi;
   for i from 2 to nops(vals[2]) do
    if vals[4][p[i]]=1 then
     QMline:=QMline,";",convert(vals[5][i],string)  
    else
     QMline:=QMline,";"
    fi;
    ansline:= ansline,";",convert(vals[5][i],string);
    if vals[6]=checkboxspreadvert then
     line:= line,[convert(cat(vals[5][i],".   "),symbol),vals[2][p[i]]]
    else
     line := line, convert(cat(vals[5][i],".   "),symbol),vals[2][p[i]]
    fi;
   od:
   ansline:=ansline,"]";
  fi;
  if vals[6]=checkboxspread  or vals[6]=radiospread then
   if vals[6] = checkboxspread then
    atype:=B
   else
    atype:=L
   fi;  
   line := NULL:
   nm := vals[17][1]*vals[17][2]:
   if nops(vals[2]) > nm then
    vals[17]:=[1,nops(vals[2])]
   fi;
   for i from 1 to vals[17][1] do
    subline := NULL:
    for j from 1 to vals[17][2] do
     ij := (i-1)*vals[17][2]+j:
     if ij <= nops(vals[2]) then
      subline:= subline,convert(cat(vals[5][ij],"."),symbol),vals[2][p[ij]]   
     else
      subline :=subline,` `,` `
     fi;               
    od;
    line := line,[subline]
   od;
   ansline:="A",atype,"_[",convert(vals[5][1],string);
   if vals[4][p[1]]=1 then
    QMline:=QMline,";",convert(vals[5][1],string)  
   elif vals[4][p[1]]=0 and vals[6] = checkboxspread then
    QMline:=QMline,";"  
   fi;
   for i from 2 to nops(vals[2]) do
    if vals[4][p[i]]=1 then
     QMline:=QMline,";",convert(vals[5][i],string)  
    elif vals[4][p[i]]=0 and vals[6]=checkboxspread then
     QMline:=QMline,";"
    fi;
    ansline:= ansline,";",convert(vals[5][i],string);
   od:
   ansline:=ansline,"]\n";
  fi;

  if member(vals[3],{0, none,`n`}) then
   vals[3]:="0_";
  elif member(vals[3],{1,after,`a`}) then
   vals[3]:="1_"
  elif member(vals[3],{2,before,`b`}) then
   vals[3]:="2_"
  elif member(vals[3],{3,afterbefore,beforeafter,`ab`,`ba`}) then
   vals[3]:="3_"
  else
   vals[3]:="4_"
  fi;
  if vals[8] = first or vals[8] = only then
   probline :=  vals[3],op(vals[1])
  fi ;
  if vals[8] = middle or vals[8] = last then
   probline := probline,vals[3],op(vals[1])
  fi;

  if member(vals[6],{checkboxspread, radiospread,checkboxspreadvert,
     checkboxspreadhorz,radiospreadvert,radiospreadhorz}) then
   if member(vals[6],{checkboxspreadhorz,radiospreadhorz}) then
    line := SPREAD([[line]]) else line:= SPREAD([line]);
   fi;
   probline := probline,line, [ansline,"\n"] ;
  elif vals[6] = spreadbox then
    probline:=probline,["TABLEOPTIONS_",vals[19],"_"],
      SPREAD(convert( M,listlist)),["TABLEOPTIONS_border=\"0\"_"]
  elif vals[6]=crossword or vals[6]=radiolabelled or vals[6]=checkboxlabelled then
   probline:=probline,ansline  
  else
   probline:= probline, [ansline]  
  fi;
  if vals[16]<>none then
   probline:=probline,op(vals[16])
  fi;

 if length(vals[22][1])>0 then
  if nops(vals[22])=1 then  
   probline:= probline,["\nAH_[0;",vals[22][1],";Show Video]\nlt_b
    gt_Click for a Video solution: lt_/b gt_"]
  elif nops(vals[22])=2 then
   probline:= probline,["\nAH_[0;",vals[22][1],";",vals[22][2],"]\nlt_b
    gt_Click for a Video solution: lt_/b gt_"]
  else
   probline:= probline,["\nAH_[0;",vals[22][1],";",vals[22][2],"]\nlt_b
    gt_",vals[22][3],"lt_/b gt_"]
  fi
 fi:

 if HARDCOPY_ = "yes" then
  probline:= probline,[vspace(5)];
 fi;

 if vals[8]=last or vals[8] = only then
  if type(PNUM_,integer) then
   PNUM_:=PNUM_+1:
   mcprint("Number ",PNUM_)
  fi:
  if vals[7]<>none then mcprint("T_\n");
   if type(vals[7],string) then
    mcprint(vals[7])
   else
    for i from 1 to nops(vals[7]) do
     if type(vals[7][i],string) then
      mcprint(vals[7][i])
     elif type(vals[7][i],list) then
      mcprint(op(vals[7][i]))
     elif op(0,vals[7][i])=SPREAD then
      nm:=cat(jack,convert(rand(),string));   
      Spread[CreateSpreadsheet](nm);
      Spread[SetMatrix](nm,convert(op(1,vals[7][i]),matrix))
     elif type(vals[7][i],function) and op(0,vals[7][i])=Lineit then
      for j in [lineit(op(vals[7][i]))] do
       if type(j,list) then
        mcprint(op(j))
       elif type(j,string) then
        mcprint(j)
       else
        print(j)
       fi
      od ;
     else
      print(vals[7][i]);  
     fi
    od;
   fi;
   mcprint("\nSKIP_");
  fi;

  QMline:=convert(vals[11],string),QMline;
  #if vals[6]=ungraded or vals[9]=survey then
  if  vals[9]=survey then
   QMline:="\nQN_[",QMline
  elif vals[9]=yes then
   QMline:="\nQM_N[",QMline
  elif vals[9]="author" then
   QMline:="\nQA_[",QMline
  else
   QMline:="\nQM_[",QMline
  fi;
  if vals[24]<>"" then
   if type(vals[24],list) then
    if nops(vals[24])=2 and member(convert(vals[24][2],string),{"1","2","3","4","5"}) then
   vals[24] :=StringTools[Substitute](vals[24][1],":",
          cat("_",vals[24][2],":"));
    else
   jack := NULL;
    for i from 1 to nops(vals[24])-1 do
     #mcprint(vals[24][i]);
     if type(vals[24][i],list) then
     vals[24][i][1]:=StringTools[Substitute](vals[24][i][1],":",cat("_",vals[24][i][2],":"));   
     jack := jack,vals[24][i][1],";"
     else jack := jack,vals[24][i],";" fi;
    od;
if type(vals[24][nops(vals[24])],list) then    
jack := cat(jack,StringTools[Substitute](vals[24][nops(vals[24])][1],":",cat("_",vals[24][nops(vals[24])][2],":"))) else
jack := cat(jack,vals[24][nops(vals[24])]) fi;
        vals[24] := jack;
   fi fi;  
   QMline := QMline,"][",vals[24],"]\n"   
  else
   QMline := QMline,"]\n"
  fi;
  mcprint(QMline);  
    
  for i from 1 to nops([probline]) do
   if member(probline[i],{"0_","1_","2_","3_"}) then
    mcprint("AH_[",ah[probline[i]],"]")
   elif probline[i]="4_" then
    next  
   elif probline[i]=NULL then
    next
   elif type(probline[i],list)  then
    mcprint(op(probline[i]))
   elif op(0,probline[i])=SPREAD then  
    nm:=cat(jack,convert(time(),string),convert(rand(),string));   
    Spread[CreateSpreadsheet](nm);
    Spread[SetMatrix](nm,convert(op(1,probline[i]),matrix));
    if vals[3]="2_" and member(vals[6],{radiolabelled,checkboxlabelled,radio,
       radiospread,checkboxspread}) then
     mcprint("lt_br /gt_")
    fi;
   elif op(0,probline[i])=MCPIECEWISE then
    print(mcpiecewise(op(op(1,probline[i]))))
   elif type(probline[i],string) then
    mcprint(probline[i])  
   else
    print(probline[i]);  
   fi;
  od;
  mcprint("\nSKIP_");
  QMline:='QMline':
  probline:='probline':
 fi;   

 RETURN(NULL)
end:
###end generator

###chkp
chkp:=proc(ans,er)
  global CHK_;
  local rel,err,reler,bot;
 if CHK_=on and type(evalf(ans),float) then
  err:=parse(convert(er,string)):
  if evalf(abs(ans))=0 then bot := evalf(abs(ans)+1) else bot:=evalf(abs(ans)) fi;
  rel:=abs(err)/bot:reler:=roundit(evalf(rel*100,4),Places=2):
  if err<=0 then NULL
  else   
  if rel<10^(-4) or rel>10^0 then  print (cat("The allowable absolute error , ",convert(er,string),", for the answer ",convert(ans,string)," is ",reler,"% of the answer.\nDo you want to modify the precision? Make it negative to switch to relative error.")) fi
fi;
fi; NULL end:


###chkf
chkf:=proc(f,rngk)
  global CHK_,RNGCHK_;
  local b,c,i,r,a;
  r := cat("Change the check values for the  function.",convert(f,string)," ");
  b:=rngk[2]-rngk[1];
  c:=rngk[1]:
  if CHK_=on then
    
   for i from 0 to 10 do
   try
      a:=evalf(subs(op(indets(evalf(f),symbol))=c+i*b/10.,f));#print(c+i*b/10.,a);
       if abs(evalf(Im(a)))>0.001  then error cat("Complex range. ",r) fi;
       if a=Float(infinity)
           then error cat("Division by zero. ",r) fi;
      
catch:
   error
end try;
end do;
  fi;
  NULL: end:

###tagit


tagit := proc()
 local n,i,plist,defaults,retain,clean,prep,key,forgen,C,W,S,E,F,qtype,finalproc5;
 global LATEX_;
 retain:={hidden,precision,anstype,answers,rightanswers,brks,Alabels,txtboxsize,
 funstuff,randomize,matsize,pretext,standards};
 if evaln(ERROR_)=ERROR_ then MCdefaults() fi;

finalproc5 := proc(lst)
   local n,i,j,k,nlst,p,m,r,lust,l;
   n := nops(lst);
  lust:=NULL:
   p := ERROR_;
   for i from 1 to n do
      m:=0;
      for j in lst[i] do
        if type(j,equation) then if lhs(j)=precision then p:= rhs(j) fi;             if type(j,equation) and lhs(j)=funstuff then m := m+1; fi fi;
      od;
   l:=NULL:r:=0;
   for j in lst[i] do
        if not type(j,equation) then l := l,j fi;
        if type(j,equation) and not lhs(j)=funstuff then l:=l,j fi;
        if  type(j,equation) and lhs(j)=funstuff then r:=r+1;
            if m = r then l := l,j  fi fi;
        
          od;
      lust:=lust,[l];   
   od;
   lust:=[lust]:
   for i in lust do    
       for j in i do
        if type(j,equation) and
          member(rhs(j),{numericbox,numberbox,textbox})
          then for k in i do
           if type(k,equation) and lhs(k)=rightanswers then
              chkp(rhs(k),p); break; fi
           od
        elif type(j,equation) and lhs(j)=funstuff and
          type(rhs(j),list)
          then for k in i do
           if type(k,equation) and lhs(k)=rightanswers then
              chkf(rhs(k),[rhs(j)[3],rhs(j)[4]]);break fi;
          od
       elif type(j,equation) and lhs(j)=ansmat then for k in rhs(j) do
           if type(k,list) and nops(k)=2 and convert(k[1],string)="C"
              then chkp(k[2],p)
           elif type(k,list) and nops(k)=2 and convert(k[1],string)="F" then chkf(k[2],RNGCHK_)
           elif type(k,list) and nops(k)=3 and convert(k[1],string)="F" then chkf(k[2],[k[3][3],k[3][4]])
           fi od
        fi;
        od od;
lust;
 end:
  clean := proc(inlist,keepin)
  local i,tlist;
  tlist := NULL;
  for i from 1 to nops(inlist) do
   if member(lhs(inlist[i]),{op(keepin)}) then
    tlist := tlist,inlist[i]
   fi
  od;
  [tlist]
 end:

 forgen := proc(w,tp)
  local r, k, m, j,i,anstp,opts,a,l,s,t;
  r:= NULL:
  k := NULL:
  m := 0;
  s:=w;
  if not type(s[2][2],list) then
   if member(tp,{_AB,_ABlabels}) then
    ERROR(cat("The ",tp," format requires a list of alternative answers
     with each correct answer enclosed in brackets."))
   else
    ERROR(cat("The ",tp," format requires a list of alternative answers
     with the correct answer enclosed in brackets."))
   fi
  fi;

  a:=NULL:
  t:=NULL;

  for l in s[1] do  
   if lhs(l)=rightanswers then
    a:=rhs(l);
   else
    t:=t,l  
   fi
  od:
  s[1]:=[t];
  if not a=NULL then
   if type(a,list) then
    s[2][2]:= a
   else
    for j from 1 to nops(s[2][2]) do
     if a=s[2][2][j] then
      s[2][2][j]:= [a]
     fi;
    od
   fi
  fi;

  for j from 1 to nops(s[2][2]) do
   if whattype(s[2][2][j])=list then
    if whattype(op(s[2][2][j]))=list then
     ERROR("An answer cannot be a list.")
    else
     r := r,op(s[2][2][j]):
     k := k,1:
     m := m+1:
    fi
   else
    if whattype(op(s[2][2][j]))=list then
     ERROR("A distractor cannot be a list.")
    else
     r := r,s[2][2][j]:
     k:= k,0
    fi
   fi:
  od;
  if nops([r]) < 2 and not member(tp,{_AB,_ABlabels}) then
   ERROR(cat("The ",tp," format requires a list of 2 or more alternative
    answers with the correct answer enclosed in brackets."))
  fi;
  if m = 0 then
   k := 1,seq(k[i],i=2..nops([k]))
  fi;
  if m > 1 and not member(tp,{_AB,_ABlabels}) then
   ERROR(cat("The ",tp," format expects only one correct answer."))
  fi;
  if tp = _AS then
   opts:=anstype=selection;
  elif tp = _AL then
   opts:=anstype=radio
  elif tp = _ALlabels then
   opts:=anstype=radiolabelled
  elif tp = _AR then
   opts:=anstype=vradio
  elif tp = _AB then
   opts:=anstype=checkbox
  elif tp = _ABlabels then
   opts:=anstype=checkboxlabelled
  fi;
  opts:=opts,answers=[r],rightanswers=[k],op(s[1]);
  if nops(s[2])>2 then
   opts := opts,aftertext=[seq(s[2][j],j=3..nops(s[2]))]
  fi;
  opts;
 end:


 prep := proc(Lst)
  local prob,opts,fun,plist,anst,s,i,v,r,j,k,l,l1,l2,ltemp,li,m,s1,s2,
        bill,sam,jack,sue,jane,tp,lsti,flag,fl,p,pp,w,
        tags,lst,lsttmp,ans,ltmp;

  prob := NULL:
  l1:=NULL;
  for l in Lst do
   if type(l,list) then
      l2:=NULL;ltmp:=NULL;
      for li in l do
          if type(li,function) and StringTools[IsPrefix]("_A",convert(op(0,li),string)) then
            if ltmp <>NULL then
            l2 := l2,[ltmp],li; ltmp:= NULL:
            else l2:=l2,li fi;
          else ltmp:= ltmp,li
          fi;
      od;
      if ltmp<>NULL then l2:=l2,[ltmp] fi;
      l1:=l1,l2;
    else l1 := l1,l fi;
  od;    
  l1:=[l1];
  #mcprint(l1);
  lst := NULL:
  for l in l1 do
     if type(l,array) then
    lst:= lst,evalm(l)
   elif type(l,function) and member(op(0,l),{Brak,Vspace}) then
    if op(0,l)=Brak then  
     lst:=lst,["\nlt_br/gt_"]
    else
     lst := lst
    fi;
   ##here
   elif type(l,function) and op(0,l)=Lineit then
    if member(true, {seq(member(op(0,l[i]),{_AN,_AC,_AS,_AF,_AE,_AW,_AI}),
      i=1..nops(l))}) then
     lst:= lst,lineit(op(l))
    else
     lst:= lst,lineit(op(l))
    fi;
   elif type(l,function) and op(0,l)=_TP then
    lst := lst
   elif type(l,function) and op(0,l)=Maketable then
    lst := lst,maketable(op(l)); #mcprint(op(l))
   else
    lst:= lst,l
   fi;
  od;
  lst := [lst,_TP()]:

  ans:= NULL:
  plist:= NULL:
  fun := NULL:
  opts:=NULL:
  key := NULL:
  tags := {_TP,_AZ,_AN,_AC,_AS,_AW,_AL,_AF,_AI,_AE,_AB,_ABlabels,_AL,
   _ALlabels,_AX,_AR,_Ar,_Aq,_AT,_ATspread,_ATcross}:
  for i from 1 to nops(lst) do
   flag := 0;
   #here
   if type(lst[i],list) then
    fl := 0;
    for j from 1 to nops(lst[i]) do
     if (not type(lst[i][j],`=`)) or  (type(lst[i][j],`=`) and not         
        member(lhs(lst[i][j]),{problem,answers,brks,rightanswers,Alabels,
        anstype,pretext,call,hidden,txtboxsize,
        precision,ansmat,incidmat,funstuff,randomize,
        aftertext,matsize,cellcolor,tableoptions,Flabels,
        inline,video,expressioncheck,standards})) then
      fl := 1
     fi;
     if type(lst[i][j],list) and member(lst[i][j][1],tags) then
      fl:=2;
     fi;
     if type(lst[i][j],function) and member(op(0,lst[i][j]),tags) then
      fl:=2;
     fi;
    od;
  
    if fl = 0  then
     plist:=plist,lst[i];
     next  
    fi;
    if fl = 2 then
     print(lst[i]);
     ERROR(cat("Do not enclose tags ",tags," in a list in Maketable. use maketable instead"))
    fi
   fi;

   #if type(lst[i],list) and type(lst[i][1],`=`) and member(lhs(lst[i][1]),{standards,
   #problem,pretext,anstype}) then plist:=plist,lst[i]; next fi;

   if type(lst[i],list) and member(lst[i][1],tags) then
    flag:=1;
    s1 := NULL:
    s2 := NULL:  
    lsti:= lst[i]:
    for k from 1 to nops(lsti) do
     if type(lsti[k],`=`) and member(lhs(lsti[k]),{brks,Alabels,hidden,
        txtboxsize,precision,funstuff,randomize,rightanswers,anstype,
        aftertext,matsize,standards,cellcolor,tableoptions,Flabels,
        inline}) then
      s1 := s1,lsti[k]
     else
      s2 :=s2,lsti[k]
     fi
    od:
   fi;
   if type(lst[i],function) and member(op(0,lst[i]),tags) then
    flag:=1:
    s1 := NULL:
    s2 := NULL:
    tp := op(0,lst[i]):
    lsti:=[tp,op(lst[i])]:
    for k from 1 to nops(lsti) do
     if type(lsti[k],`=`) and member(lhs(lsti[k]),{brks,Alabels,#hidden,
       txtboxsize,standards,precision,funstuff,randomize,rightanswers,anstype,
       aftertext,matsize,cellcolor,tableoptions,Flabels,
       inline}) then
      s1 := s1,lsti[k]
     else
      s2 :=s2,lsti[k]
     fi
    od:
   fi;
   if flag = 1 then
    s := [[s1],[s2]];
    prob := problem=[prob]:
    if lsti[1]=_AZ then
    opts := opts,hidden="author",anstype=zbox,rightanswers=lsti[2];    
    elif lsti[1]=_Aq then
    opts := opts,anstype=qbox,answers=lsti[2];
    elif lsti[1]=_Ar then
    opts := opts,anstype=sradio,answers=lsti[2];
    elif lsti[1]=_AN then
    opts := opts,anstype=numericbox,rightanswers=lsti[2],op(s[1]);
    elif lsti[1]=_AC then #chkp(lsti[2]);
     opts := opts,anstype=numberbox,rightanswers=lsti[2],op(s[1]);
     if nops(s[2])>2 then
      opts := opts,aftertext=[seq(s[2][j],j=3..nops(s[2]))]
     fi:
     if not member(txtboxsize,map(lhs,[opts])) then
      opts := opts,txtboxsize=BOXLENGTH_
     fi:
    elif lsti[1]= _AW then
     if type(lsti[2],string) then
      r:=lsti[2]
     else
      r:= cat(convert(lsti[2][1],string),seq(cat("#",convert(lsti[2][k],string)),
        k=2..nops(lsti[2])))
     fi:
     opts  := opts,anstype=wordbox,
     rightanswers=r,op(s[1]);
     if nops(s[2])>2 then
      opts := opts,aftertext=[seq(s[2][j],j=3..nops(s[2]))]
     fi:
     if not member(txtboxsize,map(lhs,[opts])) then
      opts := opts,txtboxsize=WBOX_
     fi:
    elif lsti[1]= _AT then
     bill := NULL:
     jack := NULL:
     for j from 1 to nops(lsti[2]) do  
      sam := NULL:
      sue := NULL:
      for k from 1 to nops(lsti[2][1]) do
       if type(lsti[2][j][k],list) then
        sue := sue,1;  
        sam := sam,op(lsti[2][j][k])
       else
        sue := sue,0;
        sam:= sam,lsti[2][j][k]
       fi
      od;
      bill := bill,[sam]:
      jack := jack,[sue]:
     od;
     opts := opts,anstype=tablebox,
       ansmat=matrix([bill]),incidmat=matrix([jack]),op(s[1]);
     if nops(s[2])>2 then
      opts := opts,aftertext=[seq(s[2][j],j=3..nops(s[2]))]
     fi:
     if not member(txtboxsize,map(lhs,[opts])) then
      opts := opts,txtboxsize=BOXLENGTH_
     fi:
    elif lsti[1]= _ATspread then
     bill := NULL:
     jack := NULL:
     for j from 1 to nops(lsti[2]) do  
      sam := NULL:
      sue := NULL:
      for k from 1 to nops(lsti[2][1]) do
       if type(lsti[2][j][k],list) then
        sue := sue,1;  
        sam := sam,op(lsti[2][j][k])
       else
        sue := sue,0;
        sam:= sam,lsti[2][j][k]
       fi
      od;
      bill := bill,[sam]:
      jack := jack,[sue]:
     od;
     opts := opts,anstype=spreadbox,
       ansmat=matrix([bill]),incidmat=matrix([jack]),op(s[1]);
     if nops(s[2])>2 then
      opts := opts,aftertext=[seq(s[2][j],j=3..nops(s[2]))]
     fi:
     if not member(txtboxsize,map(lhs,[opts])) then
      opts := opts,txtboxsize=BOXLENGTH_
     fi:
    elif lsti[1]= _ATcross then
     jack := NULL:
     for r in lsti[2] do
      k := NULL:
      for p in r do
           if type(p,list) and nops(p)=2 and type(p[2],list) then
           k:=k,[F,p[1],(p[2])]
 
       elif type(p,list) and nops(p)=1 then
        if type(op(p),string) then
         k := k,[W,op(p)]
        elif type(op(p),list) then
         p := op(p):
         if not type(p[1],list) then pp := p[1] else pp:=op(p[1]) fi:
         for w from 2 to nops(p) do
         if type(p[w],list) then pp:= op(p[w]),pp else pp:=pp,p[w] fi:
         od:
         k := k,[S,[pp]]
        elif nops(indets(op(p),symbol))=1 then
         k := k,[F,op(p)]
        elif nops(indets(op(p),symbol))>1 then
         k := k,[E,op(p)]
        else
         k := k,[C,op(p)]
        fi;
       else
        k := k,p
       fi;
      od;  
      jack := jack,[k];
     od;
     lsti[2] :=[jack];
     for r in lsti[2] do
      for p in r do
       if type(p,list) and not member(p[1],{C,W,F,E,S}) and
          not member(convert(p[2],string),{"aquamarine", "black", "blue", "navy",
            "coral", "cyan", "brown", "gold", "green", "gray", "grey",  "khaki",
            "magenta", "maroon", "orange", "pink", "plum", "red", "sienna",
            "tan","turquoise", "violet", "wheat", "white", "yellow"}) then
        ERROR("check color in ATcross")
       fi
      od
     od:
     opts := opts,anstype=crossword,
       ansmat=matrix(lsti[2]),op(s[1]);
     if nops(s[2])>2 then
      opts := opts,aftertext=[seq(s[2][j],j=3..nops(s[2]))]
     fi:
     if not member(txtboxsize,map(lhs,[opts])) then
      opts := opts,txtboxsize=WBOX_
     fi:
    elif member(lsti[1],{_AF,_AI}) then #chkf(lsti[2]);
     if lsti[1]=_AF then
      anst := functionbox
     else
      anst := integralbox
     fi:
  
     fun := op(indets(lsti[2],symbol));
     if nops([fun])=0 then
      fun:=x
     fi;
     if nops([fun])>1 then
      ERROR("Use AE format, not AF")
     fi;
     if nops(s[2])= 2 or nops(s[2][3])=0 then
      fun := [fun,6,op(RNGCHK_)];
     elif nops(s[2][3])=1 then
      fun := [fun,s[2][3][1],op(RNGCHK_)];
     elif nops(s[2][3])=3 then
      fun := [fun,s[2][3][1],s[2][3][2],s[2][3][3]];
     else
      ERROR("Check AF format")
     fi;
     opts  := opts,anstype=anst,rightanswers=lsti[2],funstuff=fun,op(s[1]);
     if not member(txtboxsize,map(lhs,[opts])) then
      opts := opts,txtboxsize=WBOX_
     fi:
     if nops(s[2])>3 then
      opts := opts,aftertext=[seq(s[2][j],j=4..nops(s[2]))]
     fi
    elif lsti[1]=_AE then
      #v := [op(indets(lsti[2],symbol))]; #AEstuff
      v := [op(indets(lsti[2],symbol))];       
     if nops(v)=0 then
      v:=[x]
     fi:
     r := cat(";",convert(RNGCHK_[1],string),";",convert(RNGCHK_[2],string));
     fun := convert(cat(nops(v),seq(cat(";",v[j]),j=1..nops(v)),";"),string);
     if nops(s[2])=2 or nops(s[2][3])=0 then
      fun := cat(fun,5^(min(2,nops(v))),seq(r,k=1..nops(v)))
     elif nops(s[2][3])=1 then
      if type(s[2][3][1],string) then
       fun := cat(fun,s[2][3][1])
      else
       fun := cat(fun,s[2][3][1],seq(r,k=1..nops(v)))
      fi
     elif nops(s[2][3])=3 then
      r := cat(";",s[2][3][2],";",s[2][3][3]);
      fun := cat(fun,s[2][3][1],seq(r,k=1..nops(v)))
     fi;
     opts  := opts,anstype=mfunctionbox,rightanswers=lsti[2],funstuff=fun,op(s[1]);
     if not member(txtboxsize,map(lhs,[opts])) then
      opts := opts,txtboxsize=WBOX_
     fi:
     if nops(s[2])>3 then
      opts := opts,aftertext=[seq(s[2][j],j=4..nops(s[2]))]
     fi
    elif  lsti[1] = _AX then
     opts  := opts,anstype=ungraded,op(s[1]);

     if not member(txtboxsize,map(lhs,[opts])) then
      opts := opts,txtboxsize=4
     fi:
     #if nops(s[2])>1 then opts := opts,aftertext=[seq(s[2][j],j=2..nops(s[2]))] fi
    elif  member(lsti[1],{ _AS,_AL,_AR,_ALlabels,_AB,_ABlabels}) then
     opts := opts,forgen(s,lsti[1])
    elif lsti[1]=_TP then
     k := nops([plist]):
     if k=0 then
      opts :=opts,anstype=userdefined,rightanswers="",answers=""
     else
      tp :=op([plist][-1]):  
      plist := seq([plist][j],j=1..k-1);
      opts:= opts,aftertext=rhs(prob);
      prob:= tp
     fi
    fi:
    plist := plist,[prob,opts]:
    prob:= NULL:
    opts :=NULL:
   elif type(lst[i],`=`) and member(lhs(lst[i]),{standards,pretext,brks,Alabels,
     hidden,txtboxsize,precision,funstuff,randomize,rightanswers,anstype,
     aftertext,matsize,cellcolor,tableoptions,Flabels,standards,
     inline}) then
  
          
    opts := opts,lst[i]
   #elif type(lst[i],function) and op(0,lst[i])=Lineit then
    #prob:= prob,lineit(op(lst[i]))
   else
    prob := prob,lst[i]
   fi:
  od:
 
  RETURN(plist)
 end:
 
 if PRINT_ = "yes" then
  ERROR("That option has been removed.");
  RETURN(NULL)
 fi:

 if LATEX_ = yes or LATEX_=both then
  if whslatex(Test=yes)=yes  then
   whslatex(args);
   if LATEX_=yes then
    RETURN(NULL)
   fi ;  
  else
   mcprint("To get latex output, you need to load the latextools module.
    See http://wwww.msc.uky.edu/carl/MCtools_page.htm.
    Note: If you have already loaded the latextools module,
    reload the MCtools package.");       
   RETURN(NULL)
  fi
 fi:

 if nargs=0 then
  plist:=[problem=[["What is 2 + 3?"]],anstype=textbox,rightanswers=5],
    [problem=[["What is 7 - 3?"]],anstype=radio,answers=[4,3,6,2,5],rightanswers=4]
 else
      
  plist := prep([args]);
 fi;
 #mcprint( [plist]);
 plist:=(finalproc5([plist]));
 #mcprint(plist);
 n := nops(plist);
 if n > 1 then
  defaults:=plist[1];
   
  generator(op(plist[1]),call=first);
  if n > 2 then
   for i from 2 to n-1 do
    defaults:=clean(defaults,retain);
    defaults:=PARAMS(defaults,plist[i])[1];
    generator(op(defaults),call=middle)
   od
  fi;
  defaults:=clean(defaults,retain);
  defaults:=PARAMS(defaults,plist[n])[1];
  
   generator(op(defaults),call=last)  
 else
  
  generator(op(op(plist)));
  
  #generator((plist))
 fi;
end:
###end tagit


###prints out the HTML tags
###substituted for by zipit
###htmltable
htmltable:=matrix([["spc_", "&nbsp;&nbsp;"], ["lt_", "<"], ["gt_", ">"], ["amp_", "&"], ["cup_", "&cup;"], ["cap_", "&cap;"], ["sub_", "&sub;"], ["sup_", "&sup;"], ["nsub_", "&nsub;"], ["supe_", "&supe;"], ["sube_", "&sube;"], ["isin_", "&isin;"], ["notin_", "&notin;"], ["ge_", "&ge;"], ["le_", "&le;"], ["ni_", "&ni;"], ["bld_", "<b>"], ["dlb_", "</b>"], ["unl_", "<u>"], ["lnu_", "</u>"], ["itl_", "<I>"], ["lti_", "</I>"], ["tr_", "<tr>"], ["rt_", "</tr>"], ["td_", "<td>"], ["dt_", "</td>"], ["up_", "<sup>"], ["pu_", "</sup>"], ["dn_", "<sub>"], ["nd_", "</sub>"], ["f_red_", "<font  color=\"red\">"], ["f_stp_", "</font>"], ["<br>", " "], ["<tt>", " "], ["</tt>", " "], ["<pre>", " "], ["</pre>", " "]]):

>    ###zipit
zipit := proc(infil,path)
 local ref,z,Args,vals,         zname,hfile,zfile,outfile,cpfile,response,line,n,wqspath,original,
orighref,audiohint,wrtohint,bds,mn,nm,mathclass,title,magic,web,tableopts,       ARGS,defaults,infile,app,zip,zpath,cleanps,s,hd,mathml,modxhtml,i,buf,bill,hwdir,
 f,ptozip,target,mathcl,archiv,files,pretags,tablefilter,tfiles;
 mcprint("version ",ver);mcprint(ssystem("date /T")[2],ssystem("time /T")[2]);
 infile := infil;
 zpath:=StringTools[SubString](path,1..StringTools[FirstFromRight]("/",path)-1);
 hwdir:=StringTools[SubString](path,StringTools[FirstFromRight]("/",path)+1..-1);
 if hwdir="" then
  ERROR("Remove the trailing / from the path and reexecute zipit")
 fi;

#modified 5/15/08
 #if length(infile)>3 and StringTools[SubString](infile,-4..-1) = "html" then
 # original:= StringTools[SubString](infile,1..StringTools[FirstFromLeft](".",infile)-2)
 #else
 # original := infile;
 # infile := cat(infile,"1.html")
 #fi;

 if length(infile)>3 and StringTools[SubString](infile,-4..-1) = "html" then
  original:= StringTools[SubString](infile,1..StringTools[FirstFromLeft](".",infile)-2)
 else
  original := infile;  
 fi;
 currentdir(path);
  if  not FileTools[Exists](cat(original,"1.html"))
    and  FileTools[Exists](cat(original,".html_orig")) then

  FileTools[Rename](cat(original,".html_orig"),cat(original,"1.html")) fi;
  infile:=cat(original,"1.html");
if not FileTools[Exists](infile) then error "You must export to mathml or html before zipping." fi;
#end modified 5/15
 ARGS:=select(type,[args],`=`);
 
  if evaln(MAGIC_)=MAGIC_ then eval(MCdefaults()); MCdefaults(); fi;  
 defaults:=Zname=original,Magic=MAGIC_,Zip=yes,Webpagezip=no,
     PathtoZip="",Mathml=yes,Target="Content",Archive=no,Files={}:
 Args:=[Magic,Zname,Zip,Webpagezip,PathtoZip,Mathml,Target,Archive,Files];
 ARGS:=PARAMS([defaults],ARGS):
 vals := subs({op(ARGS[1])},Args);
 zname:=vals[2]:
 zip := vals[3]:
 magic := vals[1]:
 web := vals[4]:
 ptozip:= vals[5];
 mathml := vals[6]:
 target:=vals[7]:
 archiv:=vals[8]:
 files := vals[9]:
 tfiles := NULL:
 if files<>{} then
 for i from 1 to nops(files) do
     if type(files[i],list) then
         files[i] := [convert(files[i][1],string),convert(files[i][2],string)];
         if not StringTools[IsSuffix]("html",files[i][1])  and StringTools[Search]("poId",files[i][1])=0 then
         #mcprint(files[i][1],"bill was here");
         files[i][1]:= cat(files[i][1],".html")
         fi;
         
     else files[i] := convert(files[i],string);
         if not StringTools[IsSuffix]("html",files[i]) then
         files[i]:=[cat(files[i],".html"),files[i]] else
         files[i]:=[cat(files[i]),StringTools[SubString]
            (files[i],1..StringTools[Search](".",files[i])-1)]
         fi;
     fi;
 tfiles := tfiles,files[i]
 od;
tfiles := [tfiles]:
files:=[seq(tfiles[i][1],i=1..nops(tfiles))];
fi;
 if  StringTools[Search]("Classic",interface(version))=0 then
   mcprint("This version of zipit is designed to only work with the
   html export from the Classic interface. Zip=no is set.") ;  zip:=no fi;

 if mathml=no then premod(path,files) fi;
 if  zname=original then if  mathml=yes then app:="kde"  else app:="whs" fi;
 zname:=cat(original,app)
 fi;
 wrtohint:= "false";
 cleanps := 0;
 ref := StringTools[Char](13);
 tableopts:="border=\"0\"";
 outfile:=cat(zname,".html");
 orighref := cat("<a href=\"",original);

  ##pretags
  pretags:=proc(l)
   local line,f;
  line := l:
  
  if StringTools[Search]("<img src=\"images/",line)=0 and StringTools[Search]("H_[",line)=0 then
  line:= StringTools[SubstituteAll](line,"spc_","&nbsp;&nbsp;");
   line:= StringTools[SubstituteAll](line,"lt_","<");
   
   line:= StringTools[SubstituteAll](line,"gt_",">");
   line:= StringTools[SubstituteAll](line,"amp_","&");
   line:= StringTools[SubstituteAll](line,"cup_","&cup;");
   line:= StringTools[SubstituteAll](line,"cap_","&cap;");
   line:= StringTools[SubstituteAll](line,"sub_","&sub;");
   line:= StringTools[SubstituteAll](line,"sup_","&sup;");
   line:= StringTools[SubstituteAll](line,"nsub_","&nsub;");
   line:= StringTools[SubstituteAll](line,"supe_","&supe;");
   line:= StringTools[SubstituteAll](line,"sube_","&sube;");
   line:= StringTools[SubstituteAll](line,"isin_","&isin;");
   line:= StringTools[SubstituteAll](line,"notin_","&notin;");
   line:= StringTools[SubstituteAll](line,"ge_","&ge;");
   line:= StringTools[SubstituteAll](line,"le_","&le;");
   line:= StringTools[SubstituteAll](line,"ni_","&ni;");
   line:= StringTools[SubstituteAll](line,"bld_","<b>");
   line:= StringTools[SubstituteAll](line,"dlb_","</b>");
   line:= StringTools[SubstituteAll](line,"unl_","<u>");
   line:= StringTools[SubstituteAll](line,"lnu_","</u>");
   line:= StringTools[SubstituteAll](line,"itl_","<I>");
   line:= StringTools[SubstituteAll](line,"lti_","</I>");
   line:= StringTools[SubstituteAll](line,"tr_","<tr>");
   line:= StringTools[SubstituteAll](line,"rt_","</tr>");
   line:= StringTools[SubstituteAll](line,"td_","<td>");
   line:= StringTools[SubstituteAll](line,"dt_","</td>");
   line:= StringTools[SubstituteAll](line,"f_red_","<font  color=\"red\">");
   line:= StringTools[SubstituteAll](line,"f_stp_","</font>");
   line := StringTools[Substitute](line,ref,"");
   if line<>"" then
   line := StringTools[RegSubs]("(<a[^>]*MapleAutoBookmark[^>]*>)"=" ",line);
   line := StringTools[RegSubs]("(<[^>]*)&nbsp;([^>]*>)"="\\1\\2",line);
   line := StringTools[RegSubs]("(<[^>]*)&nbsp;([^>]*>)"="\\1\\2",line); fi;
   fi;
   #line:= StringTools[SubstituteAll](line,"<br>"," ");
   line:= StringTools[SubstituteAll](line,"<dl>","");
   line:= StringTools[SubstituteAll](line,"</dl>","");
   #line:= StringTools[SubstituteAll](line,"<br />"," ");
   line:= StringTools[SubstituteAll](line,"/ >"," />");   
   line:= StringTools[SubstituteAll](line,"<tt>"," ");
   line:= StringTools[SubstituteAll](line,"</tt>"," ");
   line:= StringTools[SubstituteAll](line,"<pre>"," ");
   line:= StringTools[SubstituteAll](line,"</pre>"," ");
line:= StringTools[SubstituteAll](line,"_brk_","<br />");
line;
end;

#table filtering
tablefilter:=proc(l)
local line;
line:=l;
  if StringTools[Search]("lt_table &nbsp;",line)>0 then
   line:=StringTools[Substitute](line,"lt_table &nbsp;","lt_table ")
  fi;
  if (StringTools[Search]("lt_",line)>0 or StringTools[Search]("gt_",line)>0) and
  StringTools[Search]("^<font color",line)>0 then
   line :=StringTools[SubString](line,StringTools[FirstFromLeft]
           (">",line)+1..StringTools[FirstFromRight]("<",line)-1);
  fi;  
    
  if StringTools[Search]("lt_table",line)>0 then
   cleanps:= cleanps +1
  fi;
  if cleanps >0 then
   s:= [StringTools[SearchAll]("lt_",line)];
   if s <> [] and s[1]>0 then
    line := StringTools[SubString](line,s[1]..-1)
   fi;
   s:= [StringTools[SearchAll]("gt_",line)];
   if s <> [] and s[-1]>0 then
    line := StringTools[SubString](line,1..s[-1]+2)
   fi;
   s:= [StringTools[SearchAll]("dt_",line)];
   if s <> [] and s[1]>0 then
    line := StringTools[SubString](line,s[1]..s[1]+2)
   fi;
   s:= [StringTools[SearchAll]("td_",line)];
   if s <> [] and s[1]>0 then
    line := StringTools[SubString](line,s[1]..s[1]+2)
   fi;
   s:= [StringTools[SearchAll]("tr_",line)];
   if s <> [] and s[1]>0 then
    line := StringTools[SubString](line,s[1]..s[1]+2)
   fi;
   s:= [StringTools[SearchAll]("rt_",line)];
   if s <> [] and s[1]>0 then
    line := StringTools[SubString](line,s[1]..s[1]+2)
   fi;

   if StringTools[Search]("</p>",line)>0 then
    line:=""
   fi;
   if StringTools[Search]("<p align",line)>0 then
    line:=""
   fi;
  fi;
  if StringTools[Search]("lt_/table",line)>0 then
   cleanps:= cleanps -1
  fi;
  line;
  end:

>     ###modxhtml
 modxhtml := proc(infil,path)
  local bill,hd,buf,line,fil,f,i,filx,pbill;
  currentdir(path);
   bill:=FileTools[ListDirectory](path);
  if mathml=no then hd:="<html>" else
  hd:="<?xml version=\"1.0\"?>
     <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\"
     \"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd\" [
    <!ENTITY mathml \"http://www.w3.org/1998/Math/MathML\">]>
    <html xmlns=\"http://www.w3.org/1999/xhtml\">":

>      fi;
 

>      f := proc(infil,a)
   if

not StringTools[IsSuffix](".xhtml",a) and (
(  #not StringTools[IsSuffix](".xhtml",a) and      
     StringTools[WildcardMatch](cat(infil,"[0-9]*.html"),a)
 and not StringTools[WildcardMatch](cat(infil,"1.html"),a)  
) or
     StringTools[WildcardMatch](cat("hint","[0-9]*.html"),a)
     or member(a,files) )   
   then
    true
   else
    false
   fi
  end:
  

>      for fil in bill do
     
   if f(infil,fil) then
    buf := NULL:
    if FileTools[IsOpen](fil) then
     close(fil)
    fi;
    open(fil,READ);
    line := readline(fil);
    while line <> 0 do
###filterothersections
           #mcprint(fil,files);   
           if (member(fil,files) or ( mathml=yes and member(StringTools[Substitute](fil,".html",".xhtml"),files) )) and
        max(op(StringTools[Search](["<title", "</title","<html","</html","<head","</head","<body",
        "</body"],line)))>0 then line:= readline(fil); next; fi;
line:= tablefilter(line);
    line := pretags(line);
     if StringTools[Search]("<dl>",line)>0 then  
      line := StringTools[Substitute](line,"<dl>","")
     fi;
     if StringTools[Search]("</dl>",line)>0 then  
      line := StringTools[Substitute](line,"</dl>","")
     fi;
     if StringTools[Search]("/ >",line)>0 then  
      line := StringTools[Substitute](line,"/ >","/>")
     fi;
     if StringTools[Search]("<basefont",line)>0 or
        StringTools[Search]("</basefont",line)>0 then
      line :=readline(fil); next;
     fi;
     buf:=buf,line;
     line:= readline(fil);
    od:
    close(fil);
    open(fil,WRITE);
    #mcprint(fil,files);
    if member(fil,files) or member(StringTools[Substitute](fil,".html",".xhtml"),files) then NULL
    else  
      writeline(fil,hd) fi;
    for i from 1 to nops([buf]) do
     writeline(fil,buf[i]);
    od:
    close(fil);
if mathml = yes then
   
filx := StringTools[Substitute](fil,".html",".xhtml");
     #mcprint(fil,filx);
     if FileTools[Exists](filx) and filx<>fil then
     FileTools[Remove](filx);
    

    fi;
    FileTools[Rename](fil,filx);
    
 fi; #end if mathml=yes
   fi
  od:
  NULL;
 end:
 ###end modxhtml

>   
 currentdir(path);

 if StringTools[Search]("-",convert(magic,string))=0 then
 audiohint :=cat("https://www.mathclass.org/Homes/",magic,"/hws/",zname);
 mathclass :=
   cat("<a href=\"https://www.mathclass.org/Homes/",magic,"/hws/",zname,"/");
 else
audiohint  :=cat("https://www.mathclass.org/WebPages/Homes/",magic,"/hws/",zname);
mathclass :=
cat("<a href=\"https://www.mathclass.org/WebPages/Homes/",magic,"/hws/",zname,"/");
fi:
 if vals[4]=no then
  mcprint("Have you saved the source worksheet lately?");
  mcprint(cat("Files in ",currentdir()," will go in homework zipfile."));
  
  

wqspath:=cat(mathclass,original);
 else
  mcprint(cat("Your files for this webpage should be in ",currentdir(),"."));
  mathclass:=cat("<a href=\"http://www.mathclass.org/Homepages/",magic,"/",original);
  wqspath:=mathclass;
 fi;
 if target="Content" then
  mathclass:= cat(mathclass,"\"  Target=\"Content")
 fi:
 try
  fopen(infile,READ,TEXT)
 catch "file already open":
  fclose(infile);
  fopen(infile,READ,TEXT);
 end try;

 buf := NULL:
 line:= readline(infile):
 if mathml=no then

>     for i from 1 to 2000 while line<>0 do
  if StringTools[Search]("math xmlns=",line)>0 then
   mathml:=yes; mcprint("Mathml is detected.  Mathml=yes is set.");
   break
  fi;  
  line:=readline(infile)
 od:
 fi;
 if FileTools[IsOpen](infile) then
  fclose(infile);
  fopen(infile,READ,TEXT)
 else
  fopen(infile,READ,TEXT)
 fi;

>     if mathml=yes then
filter7(infile,path);
fi;

 

>     try
  fopen(outfile,WRITE,TEXT)
 catch "file already open":
  fclose(outfile);
  fopen(outfile,WRITE,TEXT);
 end try;
 bill := FileTools[ListDirectory](path);
 for f in bill do
  if StringTools[Search]("hint",f)>0 then
     FileTools[Remove](cat(path,"/",f))
  fi
 od:
 if mathml=no then
  hd := "<html>"
 else
  hd:="<?xml version=\"1.0\"?>
     <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\"
               \"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd\" [
    <!ENTITY mathml \"http://www.w3.org/1998/Math/MathML\">
    ]>
    <html xmlns=\"http://www.w3.org/1999/xhtml\">":
 fi;
 writeline(outfile,cat(hd,"\n<head>\n<title>",infil,"whs.html</title>\n<!-- Created by Maple,
   IBM INTEL NT (modified by WHS)-->\n</head>\n<body bgcolor=\"FFFFFF\">\n<p>"));
 line := readline(infile);
 while line<>0 and not(StringTools[Search]("H_",line)>0 and
       StringTools[Search]("ch](\"H_\"",line)=0 and
       StringTools[Search]("AH_",line)=0) do
  if StringTools[Search]("MCtools:=table([]):",line)>0 then
   ERROR("Close the MCtools section, and re-export to html before using zipit.")
  fi;
  line := readline(infile)
 od;
 if line = 0  then
  fclose(infile);
  fclose(outfile);
  ERROR("You have no header (captital h underscore) for this homework")
 fi:
 while line <> 0 do

if  StringTools[Search]("H_[",line)>0 and StringTools[Search]("AH_[",line)=0 then
  if nops([StringTools[SearchAll]("]",line)])=1 and files<>{} then
   line := StringTools[SubString](line,StringTools[Search]("H_[",line)..StringTools[Search]("]",line)-1);
    line:= cat(line,";");

for i from 1 to nops(tfiles)-1 do
    if type(tfiles[i],list) then line:=cat(line,tfiles[i][1],",",tfiles[i][2],":")
    else line:=cat(line,tfiles[i][1],",",tfiles[i][2],":"); fi;
od;
if type(tfiles[nops(tfiles)],list) then line:=cat(line,tfiles[nops(tfiles)][1],",",tfiles[nops(tfiles)][2],"]")
    else line:=cat(line,tfiles[nops(tfiles)],",",tfiles[nops(tfiles)],"]") fi;
fi;
fi;

  if mathml<>no then
   if StringTools[Search](".html",line)>0 and
      StringTools[Search](cat("<a href=\"",infil),line)>0 and
      StringTools[Search](cat("<a href=\"",infil,"1.html"),line)=0 then
    line:=StringTools[Substitute](line,".html",".xhtml")
   fi;
  fi;

#tablefiltering
line:=tablefilter(line);
    if StringTools[Search]("BEGINHINT_",line)>0 and  
     StringTools[Search]("\"BEGINHINT_\"",line)=0 then
   bds := StringTools[SearchAll]("_",line);
   if nops([bds])<3 then
    fclose(infile);
    fclose(outfile);
    ERROR("Hint problem. close the MCtools section and
      re-export to html before using zipit.");  
   fi;
   hfile:=StringTools[SubString](line,bds[1]+1..bds[2]-1);
   title:=StringTools[SubString](line,bds[2]+1..bds[-1]-1);
   title:= StringTools[SubstituteAll](title,"lt_","<");
   title:= StringTools[SubstituteAll](title,"gt_",">");

   if mathml=no then
    hfile:=cat(hfile,".html")
   else
    hfile:=cat(hfile,".xhtml")
   fi;

   fopen(hfile,WRITE,TEXT);
   writeline(hfile,hd); writeline(hfile,"<p>");
   #fix
   if StringTools[Search]("\"  Target=",mathclass)>0 then
    mathcl := StringTools[Substitute](mathclass,"\"  Target=",cat(hfile,"\"  target="))
   #elif not target=no then
    #mathcl := cat(mathclass,hfile,"\"  Target=\"",target)
   else mathcl:= cat(mathclass,hfile)  
   fi:
   writeline(outfile,cat(mathcl,"\"><p align=\"left\">"));
   writeline(outfile,
     cat("<b><font color=\"#000000\" size=\"3\">",title,"</font></b>"));
   writeline(outfile,"</p></a>");
   wrtohint := "true";
   line:=readline(infile);
  fi;
  if StringTools[Search]("ENDHINT_",line)>0 and
     StringTools[Search]("\"ENDHINT_\"",line)=0 then
   writeline(hfile,"</p>\n</html>");
   fclose(hfile);  
   wrtohint:="false";
   line := readline(infile)
  fi;
  ### link modification
  if  StringTools[Search]("hint.wav",line)>0  then   
   line:=StringTools[Substitute](line,"http:/",audiohint)
  
  elif  StringTools[Search]("https://local:",line)>0  then   
   line:=StringTools[SubstituteAll](line,"https://local:",audiohint)
elif  StringTools[Search]("local:",line)>0  then   
   line:=StringTools[Substitute](line,"local:","local:/");
   line:=StringTools[Substitute](line,"local:",audiohint)  
  else
   line:=StringTools[Substitute](line,orighref,wqspath)
  fi;


  line:= StringTools[SubstituteAll](line,"lt_a href=\"http://XXX.VIDEO",
    "\nlt_a href=\"http://XXX.VIDEO");
  if StringTools[Search]("TABLEOPTIONS_",line)>0 then
   bds := StringTools[SearchAll]("_",line);
   if nops([bds])=2 then
    tableopts:=StringTools[SubString](line,bds[1]+1..bds[2]-1);
    line:=StringTools[Substitute](line,
      cat("TABLEOPTIONS_",StringTools[SubString](line,bds[1]+1..bds[2]))," ")
   fi;
  fi;
  #line:= StringTools[SubstituteAll](line,"border=\"1\"",tableopts);
   line := pretags(line);
   ###putithere
     if not line="" then
   if wrtohint = "false" then
    writeline(outfile,line)
   else
    writeline(hfile,line)
   fi
  fi;
  line := readline(infile)
 od;
#checkthis
if mathml=yes then
 writeline(outfile,"</p>\n</body>\n</html>");
#print("writing bodyhtml to ",outfile);
fi;
 try
  fopen(hfile,APPEND)
 catch "file already open":
  fclose(hfile);
  fclose(infile);
  
  fclose(outfile);
  ERROR("You are missing an endhint (in capitals)"):
 end try;

 fclose(hfile);
 fclose(infile);
 fclose(outfile);
 if evaln(hfile)=hfile and FileTools[Exists](hfile) then FileTools[Remove](hfile) fi;
mcprint("Have you saved the source worksheet lately?");
 if mathml=no then modxhtml(infil,path)
 else  
  modxhtml(infil,path);
  mcprint("You are using zipit with the option Mathml=yes.  You should put
   a note at the top of the homework that IE6 and the Mathplayer plugin
   (or special fonts for Mozilla) are needed to view the homework.") fi;
  if archiv=yes then archiveit(Path=cat(path,"/"))
  elif archiv=MCtools then archiveit(Path=cat(path,"/"),Package=[MCtools])
  elif type(archiv,list) then archiveit(Path=cat(path,"/"),Package=archiv) fi;
   if zip=yes then
   FileTools[Rename](cat(infil,"1.html"),cat(infil,".html_orig"),force);  #added 2/19/08
   zfile :=cat(vals[5],"zip  -r ..\\",zname," *");
   #zfile :=cat(vals[5], "zip  -r ",zpath,"/",zname," ",path);
   #FileTools[Rename](cat(zname,".html"),cat(hwdir,"1.html"),force);
   bill := system(zfile);

   if bill>0 then
    mcprint(cat("system errorno = ",convert(bill,string),"You don't have zip (or something else is wrong).
      You need to make a zipfile. \nThe html file  ",zname,".html has
      been created in ",path,". \nNow zip the  files in that directory
      with the name ",zname,".zip and install the homework on WHS."))
    else
     mcprint(cat("A zipfile ",zname,".zip has been created in ",zpath,".
      Now install the homework via mathclass"))
    fi;
   else
    mcprint(cat("The html file ",zname,".html has been created in ",path,
     ". \nNow zip the  files in that directory with the name ",zname,
     ".zip and install the homework on WHS."))
   fi:

end:
###end zipit

>   

>    ###tableit
tableit  := proc()
 local i,j,r,tbl,tops,cols,lst,ent;
 if nargs<1 then
  ERROR("Need the number of columns and the list of entries")
 fi;
 if type(args[1],integer) then
  cols:=args[1]:
  lst:= args[2]
 else
  cols := args[2]:
  lst:=args[1]
 fi:
 r := ceil(nops(lst)/cols);
 if nargs>2 then
  tops:=(args[-1])
 else
  tops:=""
 fi;
 tbl := ah_(0),brks=-1,["lt_table ",tops," gt_"];
 for i from 1 to r do
  tbl := tbl, ["lt_tr gt_lt_td gt_"] ;
  for j from 1 to cols do
   ent := (i-1)*cols+j;
   if j < cols then
    if ent <= nops(lst) then
     tbl := tbl, lst[ent];
     if type(lst[ent],function) and
        member(op(0,lst[ent]),{_AW,_AC,_AF,_AE,_AS,_AI}) then
      tbl:=tbl,["\n"]
     fi;
     tbl:=tbl,["lt_/td gt_lt_td gt_"]
    fi;
   else
    if ent <= nops(lst) then
     tbl := tbl, lst[ent];
     if type(lst[ent],function) and
        member(op(0,lst[ent]),{_AW,_AC,_AF,_AE,_AS,_AI}) then
      tbl:=tbl,["\n"]
     fi;
     tbl:=tbl,["lt_/td gt_lt_/tr gt_"]
    fi;
   fi
  od
 od;
 tbl := tbl,["lt_/table gt_"];
 tbl
end:
###end tableit

###Line
Line:=proc ()
 local i,Args,fm;
 Args:=NULL:
 for i from 1 to nargs do
  if type(args[i],`=`) and lhs(args[i])=cellfmts then
   fm := args[i]
  else
   Args:= Args,args[i]
  fi
 od:
 Lineit([Args],fm)
end proc:
###end Line

Autoline := proc()
 local cfm,i;
 cfm := NULL;
 for i in args do
 if  hastype(i,`^`) then cfm := cfm,1 else cfm:= cfm,3 fi od:
 evaln(Line)(args,cellfmts=[cfm]) end:

###lineit
lineit  := proc(lst)
 local i,j,cols,tbl_,defaults,vals,Args,ARGS,tp,md,bt,bl,cf,b;
 if PRINT_="yes" then
  if type(lst[1],list) then
   RETURN(op(lst))
  else
   RETURN(lst)
  fi
 fi;
 tp := "lt_td valign=\"top\" gt_";
 md := "lt_td valign=\"middle\" gt_";
 bt := "lt_td valign=\"bottom\" gt_";
 bl := "lt_td valign=\"baseline\" gt_";
 cf := [tp,md,bt,bl];
 #cellfmts=[seq("lt_td gt_",i=1..40)]
 defaults:=cellfmts=[seq(2,i=1..40)],     
     startable="yes",tops="",columns=40,endtable="yes",newrow="no";
 Args:=[cellfmts,startable,tops,columns,endtable,newrow];
 ARGS:=PARAMS([defaults],select(type,[args],equation)):
 vals := subs(ARGS[1],Args);
 vals[1]:=[seq(cf[vals[1][i]],i=1..nops(vals[1]))];
 cols := nops(lst);
 b:=select(type,lst,function):
 if member(true, {seq(member(op(0,b[i]),
    {_AC,_AS,_AF,_AE,_AW,_AI}),i=1..nops(b))}) then
  tbl_:=["\n",AH_[0]],brks=-1
 else
  tbl_:=NULL
 fi;
 if convert(vals[2],string)="yes" then
  tbl_ := tbl_,["lt_table ",vals[3]," gt_lt_tr gt_"]  
 fi;  
 if vals[4] < cols then
  ERROR("Too many cells in lineit, increase columns=")
 fi;   
 for j from 1 to cols do
  if type(vals[1][j],string) then
   tbl_ := tbl_,[vals[1][j]]
  else
   tbl_ := tbl_,[cf[vals[1][j]]]
  fi;
  if type(lst[j],function) and
     member(op(0,lst[j]),{_AC,_AS,_AF,_AE,_AW,_AI}) then
   tbl_:= tbl_,lst[j],["\nlt_/td gt_"];
  else
   tbl_:=tbl_,lst[j],["lt_/td gt_"]
  fi
 od;
 if convert(vals[6],string)="yes" then
  tbl_ := tbl_,["lt_/tr gt_lt_tr gt_"]
 fi;
 if convert(vals[5],string) = "yes" then  
  tbl_ := tbl_,["lt_/tr gt_lt_/table gt_"]
 else
  tbl_:=tbl_,["lt_td gt_ "];
 fi;
end:
###end lineit

>    PCWSE:=proc(L)
local ARG,j:
ARG:=NULL:
for j from 1 to nops(L) do
ARG:=ARG,[``,L[j]]:
od:
if nops(L)<=1 then convert((cat("{  ",convert(op(L),string))),symbol) else
PIECEWISE(ARG) fi:
end:

>    ###mcpiecewise
mcpiecewise := proc()
 local f,c,i;
 f := NULL:
 c := NULL:
 for i from 1 to nargs do
  if type(args[i],list) then
   f := f,args[i];
  else
   f := f,[args[i],x <2] :
   c := c,2*i-1
  fi:
 od:
 c := [c]:
 if nops(c) = 0 then
  PIECEWISE(f)
 elif nops(c) = 1 then
  subsop(c[1]=``,PIECEWISE(f))
 elif nops(c) = 2 then
  subsop(c[2]=``,subsop( c[1]=``,PIECEWISE(f)))  
 elif nops(c)=3 then
  subsop(c[3]=``,subsop(c[2]=``,subsop( c[1]=``,PIECEWISE(f))))
 elif nops(c)=4 then
  subsop(c[4]=``,subsop(c[3]=``,subsop(c[2]=``,
    subsop( c[1]=``,PIECEWISE(f)))))
 elif nops(c)=5 then
  subsop(c[5]=``,subsop(c[4]=``,subsop(c[3]=``,
    subsop(c[2]=``,subsop(c[1]=``,PIECEWISE(f))))))
 elif nops(c)=6 then
  subsop(c[6]=``,subsop(c[5]=``,subsop(c[4]=``,
    subsop(c[3]=``,subsop(c[2]=``,subsop( c[1]=``,PIECEWISE(f)))))))
 else
  ERROR("mcpiecewise only handles 6 empty rules (so far)")
 fi
end:
###end mcpiecewise

###maketable
maketable := proc()
 local i, j, r, tbl, tops, cols, defaults, vals, Args, ARGS, Lst, Cfmts,Rfmts,lst;
 defaults := columns = 6, cellfmts = [""], rowfmts = [""],
   tablefmts = "border = \"0\"", immediate = no;
 Args := [cellfmts, columns, tablefmts, immediate, rowfmts];
 ARGS := PARAMS([defaults], select(type, [args], equation));
 vals := subs(ARGS[1], Args);
 lst := op(remove(member,[args],ARGS[1]));
 if type(lst, list) and not type(lst, listlist) then
  if nops(lst) <> nops(vals[1]) then
   if nops(vals[1]) = 1 then
    vals[1] := [seq(op(vals[1]), i = 1 .. nops(lst))]
   else
    ERROR("cellfmts and lst must be same length")
   end if
  end if;
  r := ceil(nops(lst)/vals[2]);
  Lst := NULL;
  Cfmts := NULL;
  for i to r - 1 do
   Lst := Lst, [seq(lst[(i - 1)*vals[2] + j], j = 1 .. vals[2])];
   Cfmts := Cfmts, [seq(vals[1][(i - 1)*vals[2] + j], j = 1 .. vals[2])]
  end do;
  Lst := [Lst, [seq(lst[(r - 1)*vals[2] + j], j = 1 .. nops(lst) - (r - 1)*vals[2]),
      seq([""], i = nops(lst) + 1 .. r*vals[2])]];
  Cfmts := [Cfmts, [seq(vals[1][(r - 1)*vals[2] + j], j = 1 .. nops(lst) - (r - 1)*vals[2]),
      seq("", i = nops(lst) + 1 .. r*vals[2])]]
 elif type(lst, listlist) then
  r := nops(lst);
  vals[2] := nops(lst[1]);
  Lst := lst;
  if type(vals[1],listlist) then
   if nops(vals[1]) = nops(lst) and
      nops(vals[1][1]) = nops(lst[1]) then
    Cfmts := vals[1]
   else
    ERROR("cellfmts and lst must be same size")
   fi
  elif nops(vals[1]) = 1 then
   Cfmts := [seq([seq(op(vals[1]), i = 1 .. nops(lst[1]))], j = 1 .. nops(lst))]
  else
   ERROR("cellfmts and lst must be same size")
  end if
 elif type(lst, matrix) then
  r := linalg[rowdim](lst);
  vals[2] := linalg[coldim](lst);
  Lst := lst;
  if nops(vals[1]) = 1 then
   Cfmts := [seq([seq(op(vals[1]), i = 1 ..linalg[coldim](lst))],
     j = 1 ..linalg[rowdim](lst))]
  elif linalg[rowdim](vals[1]) = linalg[rowdim](lst) and
       linalg[coldim](vals[1]) = linalg[coldim](lst) then
   Cfmts := vals[1]
  else
   ERROR("cellfmts and lst must be same size")
  end if
 else
  ERROR("Expect a list, listlist, or matrix as input.")
 end if;
 Rfmts := NULL:
 if nops(vals[5]) = r  then
  Rfmts:= vals[5]
 elif nops(vals[5])=1 then
  Rfmts:=[seq(op(vals[5]),i=1..r)]
 else
  ERROR("check your rowformats")
 fi:
 tbl := ["lt_table ", vals[3], " gt_"];
  for i to r do
  tbl := tbl, ["lt_tr",Rfmts[i]," gt_"];
  for j to vals[2] do
   tbl := tbl, [cat("lt_td", Cfmts[i,j], " gt_")], Lst[i, j], ["dt_"]
  end do;
   tbl := tbl, [" rt_"]
 end do;
 tbl := tbl, ["lt_/table gt_"];
 if vals[4] = yes then
  for i to nops([tbl]) do
   if type(tbl[i], list) then
    mcprint(op(tbl[i]))
   elif type(tbl[i], string) then
    mcprint(tbl[i])
   else
    print(tbl[i])
   end if
  end do
 else
  tbl
 end if
end proc:
###end maketable

###symbolize
symbolize := proc(value)
 local v, p, q;
 v := value;
 if nargs=2 and type(args[1],procedure) then
  args[1](op(symbolize(args[2])))
 elif nargs=2 then
  subs(symbolize(args[1]),args[2])
 elif type(v,list) or type(v,set) then
  v := map(symbolize,v);
 elif  type(v,equation) then
  if type(rhs(v), integer) or type(rhs(v), float) then
   if rhs(v) < 0 then
    v := subs(rhs(v) = `(`*convert(rhs(v), symbol)*`)`, v)
   else
    v := subs(rhs(v) = convert(rhs(v), symbol), v)
   end if
  elif type(rhs(v),fraction) then
   v := lhs(v)=symbolize(numer(rhs(v)))/symbolize(denom(rhs(v)))
  elif type(rhs(v),`^`) then
   v := lhs(v)=subsop(1=symbolize(op(1,rhs(v))),rhs(v))
  elif type(rhs(v),procedure) then
   v := lsh(v)=op(0,rhs(v))(symbolize(op(1,rhs(v))))
  else  
   v
  fi;
 else
  if type(v, integer) or type(v, float) then
   if v < 0 then
    v := subs(v = `(`*convert(v, symbol)*`)`, v)
   else
    v := subs(v = convert(v, symbol), v)
   end if
  elif type(v,fraction) then
   v := symbolize(numer(v))/symbolize(denom(v))
  elif  type(v,`^`) then
   v :=  subsop(1=symbolize(op(1,v)),v)
  elif type(v,procedure) then
   v := op(0,v)(symbolize(op(1,v)))
  else
   v
  fi;
 end if
end proc:
###end symbolize
##audiohint  :=cat("https://www.mathclass.org/WebPages/Homes/",magic,"/hws/",zname);
###addlink
addlink := proc(link,text)
local l,lnk,b;
b:="_blank";
 if nargs<2  then mcprint("addlink(link,text) adds a link to a file.
Options:
if link contains the string \"self:\" then the target is set to open _self which should open the link in the
same window. The default is to open in a separate window.    
0 if there are three arguments then the file must be uploaded to the homework file using the upload video button.
1 if link begins with \"vidwin:\" then the file must be uploaded to the homework file using the upload video button.
2 if link begins with \"local:\" then the file must be included in the homework directory zipfile
3 if link begins with \"http\" then the file must be at the url given
4 otherwise link is appended with \"http://\" and treated as in 3"); return NULL fi;
if StringTools[Search]("self:",StringTools[LowerCase](convert(link,string)))>0 then
b:="_self": lnk:= StringTools[Substitute](link,"self:",""): fi:
if nargs = 3 then
 l:=cat("\nAH_[",args[3],";",link,";",text,"]\n")
elif StringTools[Search]("vidwin:",link)>0 then
lnk := StringTools[Substitute](link,"vidwin:","");
l:=  cat("lt_a href=\"http://XXX_VIDEO/",lnk,"\" target=\"",b,"\"  gt_ ",text," lt_/a gt_")
elif StringTools[Search]("local:",link)>0 then
l:=  cat("lt_a href=\"",link,"\" target=\"",b,"\" gt_ ",text," lt_/a gt_")
elif StringTools[Search]("http",link)>0 then
l:=  cat("lt_a href=\"",link,"\" target=\"",b,"\"  gt_ ",text," lt_/a gt_")   
 else
l:=  cat("lt_a href=\"",link,"\" target=\"",b,"\"  gt_ ",text," lt_/a gt_")
 fi;
l;
end:
###end addlink


###addimg
addimg := proc(link)
local bill,defaults,help,center,latex,opts,hfill,optins,size;
  defaults:=Help=no,Center=no,Latex=no,Size=small,Hfill=no,
Options="height=90pt,width=120pt";
 opts := subs([ op(select(type,[args],`=`)),defaults],[Help,Center,Latex,Hfill,Options,Size]);
help:=opts[1]: center:=opts[2]: latex:=opts[3]: hfill:=opts[4]:
optins:=opts[5]:
size:=opts[6]:
if size=large then optins:="height=200pt,width=320pt" fi;
if help=yes then mcprint("addimg(link) adds an img tag for a picture which can be in the homwork directory or elsewhere.
Options:
Latex=no  change to yes for latex output.
Center=no change to yes to center picture (in html or latex)
Size=small change to large to set dimensions to 200 by 320
Options=\"height=90pt,width=120pt\"  change as needed (for latex)"): RETURN(NULL) fi;
if latex = yes then
bill := "\\includegraphics[";
 if hfill<>no then bill := cat(hfill,bill) fi;
 bill:=cat(bill,optins,"]{",link,"}");
 if center=yes then bill := cat("\\begin{center}\n",bill,"\n\\end{center}")  fi;  
else bill:=  cat("lt_img src=\"",link,"\" alt=\"MaplePlot\" /gt_");
if center=yes then bill:=cat("lt_center gt_ ",bill," lt_/center gt_") fi;
fi;

 
[bill];  
end:
###end addimg

###addsectionhint
addsectionhint := proc()
 local mn,t,nm,title,text,i;
 if nargs <2 then
  ERRROR("Need a message and sectionmaterial")
 fi;
 title := args[1]:
 if nargs = 2 then
  if type(args[2],list) then
   text := op(args[2])
  else
   text:=args[2]
  fi
 else
  text := [seq(args[i],i=2..nargs)]
 fi:
 mn:=cat("hint",convert(ceil(rand()+time()),string));

 ["\nBEGINHINT_",mn,"_",title,"_"],op(text),["ENDHINT_",mn,"_"];
end:
###end addsectionhint

###addvlink
addvlink := proc(path)
 local defaults,Args,ARGS,vals,bill,name;
 defaults:=server="",drives=[];
 Args:=[server,drives];
 ARGS:=PARAMS([defaults],select(type,[args],equation)):
 vals := subs(ARGS[1],Args);
 name :=StringTools[SubString](path,
    StringTools[FirstFromRight]("/",path)+1..length(path));
 if vals[1]<>"" then
  bill := addlink(cat(vals[1],"/",name)," WHS video server"),"spc_"
 else
  bill := NULL
 fi;
 bill := bill, addlink(cat("file:///d:/",path),"D") ,"spc_ ",
   addlink(cat("file:///e:/",path)," E"),"spc_ ",
   addlink(cat("file:///k:/",path)," K"),"spc_ "  ,
   addlink(cat("file:///l:/",path)," L"),"spc_ ",
   seq(op(["spc_ ",addlink(cat("file:///",vals[2][i],":/",path),
   cat(" ",vals[2][i]))]),i=1..nops(vals[2])) ;
 bill;
end:
###end addvlink

archiveit := proc()
local defaults,pkgs,path,archive,pa,opts,help,p,tmp,lib;
global savelibname;
 lib := libname;
 if whattype(lib)=`exprseq` then lib:=lib[1] fi;
 defaults := Path=lib,
 Archive="mclatools.lib",Help=no,Package=[MCtools,latextools];
 opts := subs([op(select(type,[args],`=`)),defaults],
  [Path,Archive,Help,Package]);
 path := opts[1];
 archive:= opts[2];
 help:= opts[3];
 pkgs:= opts[4];
 if help=yes then mcprint(
"archiveit(options)  saves the current MCtools and latextools to the Maple library
 options:
  Help=yes #gives this message
  Path=\"libname\", #set to a writable directory
  Note:  the default is the most common place for the Maple library to be.
  You may have to change it.
  If you are logged into a mathsciences machine try
  Path=\"c:/local/Maple95/lib\"
  Archive=\"mclatools.lib\"  #set to a writable archive
  Package=[MCtools,latextools] # set to the words you wish to save to the library");
 RETURN(NULL) fi;
 if not FileTools[Exists](path) then ERROR("The path ",path," does not exist" ) fi;
 #if not FileTools[IsWritable](path) then ERROR("You don't have permission to write in ",path) fi;
 pa := cat(path,"/",archive);
 tmp:=savelibname;
 savelibname:=pa;
 if not FileTools[Exists](pa) then
   try
   march('create',pa);
   catch "Error":
     savelibname:=tmp;
     error
   end try;     
 fi;
 if type(pkgs,list) then for p in pkgs do
  savelib(p) od
   else savelib('pkgs') fi;
 mcprint(pkgs," archived in ",pa);
 savelibname:=tmp;
 if StringTools[Search]("MCtools",StringTools[Join](pkgs))>0 then mcprint("MCdefaults() = ",MCdefaults()) else NULL fi;
 end:

###PA
PA:=proc(Center,Radius,Theta1,Theta2)
 local Args,Thknss,Styl,Clr,Scalefactor,ARGS,defaults,PLOTOPTIONS:
 defaults:= thknss=2,styl=1, clr=black, scalefactor=1:
 Args:=seq([args][j],j=5..nargs):
 ARGS:=PARAMS([defaults],[Args])[1]:
 PLOTOPTIONS:=op(PARAMS([defaults],[Args])[2]):
 Thknss:=subs(ARGS,thknss):
 Styl:=subs(ARGS,styl):
 Clr:=subs(ARGS,clr):
 Scalefactor:=subs(ARGS,scalefactor):
 plot([t->Center[1]+Radius*cos(t),t->Center[2]+Scalefactor*Radius*sin(t),
  evalf(Theta1)..evalf(Theta2)],thickness=Thknss,linestyle=Styl,color=Clr,PLOTOPTIONS)
end:
###end PA

#list qm lines in a worksheet.
###show_answers
show_answers := proc(fil,path)
 local junk,j,oc,a,b,c,d,e,defaults,opts,line,help,tag,mode,file,i,qtype;
 defaults:=Help=no,Mode="vertical",Qtype="QM";
 opts:= subs([ op(select(type,[args],`=`)),defaults],
     [Help,Mode,Qtype]);
 help:=opts[1]:
 mode := convert(opts[2],string);
 qtype:=opts[3];
 if help=yes then
  mcprint("show_answers(\"worksheet\",path) lists the answers in the qmlines in file.
     Use .mws for the source, and 1.html for the html export.  
     Use mode=\"list\" if you want the answers given in list.  
     Use mode=\"count\" to get simply the number of questions.");
  RETURN(NULL)
 fi;
 if not member(StringTools[SubString](fil,-3..-1),{"mws","tml"}) then
  file := cat(fil,".mws")
 else
  file :=  fil
 fi;
 if StringTools[SubString](file,-3..-1)="mws" then
  tag:=cat("\"",qtype,"_[")
 else
  tag:=cat(">",qtype,"_[")
 fi;
 currentdir(path);

 try
  fopen(file,READ,TEXT)
 catch "file already open":
  fclose(file);
  fopen(file,READ,TEXT);
 end try;
 line := readline(file);
 junk:= NULL:

 while line<>0 do
  junk:= cat(junk,line);
  line:= readline(file);
 od;
 fclose(file);
 a := NULL:
 b:=[StringTools[SearchAll](tag,junk)];
 for c in b do
  if StringTools[SubString](junk,c+6..c+6) ="\"" then
   next
  fi;
  d := StringTools[SubString](junk,c+5..c+200);
  e := StringTools[FirstFromLeft]("]",d);
  a := a,StringTools[SubString](d,1..e-1);
 od;
 if mode="vertical" then
  for i from 1 to nops([a]) do
   mcprint("Question ",i,"  ",a[i])
  od
 elif mode="count" then
  mcprint("Number of questions:",nops([a]))
 else
  [a]
 fi;
end:
###show_answers


stagit := proc()
local defaults,help,opts;
  defaults:=Help=no;
 opts := subs([ op(select(type,[args],`=`)),defaults],[Help]);
if opts[1]=yes then mcprint("stagit(problems); executes tagit(problems); then if Standardize
is a list, executes tagit(hidden=survey,op(Standardize). Used to make it convenient to
get teachers to key standards to problems."); RETURN(NULL) fi;

tagit(args);
if type(Standardize,list) then
tagit(hidden=survey,op(Standardize)) fi;
end:

ltagit:= proc()
local defaults,help,opts;
  defaults:=Help=no;
 opts := subs([ op(select(type,[args],`=`)),defaults],[Help]);
if opts[1]=yes then mcprint("ltagit(problems); executes latextools:-whslatex(args) if LATEX_=yes else \nit executes tagit(args)."); RETURN(NULL) fi;
  if LATEX_=yes then latextools:-whslatex(args) else tagit(args) fi end:

format:= proc(txt)
local defaults,help,size,bold,ital,undln,cntr,clr,text,opts,ftable,gtable;
  text:=txt;
defaults:=Help=no,Size="large",Color="blue",Bold=yes,
Underline=no,Italics=no,Center=no;
 opts := subs([ op(select(type,[args],`=`)),defaults],[Help,Size,Color,Bold,Underline,Italics,Center]);
 help:=opts[1]: size:=opts[2]: bold:=opts[4]:undln:=opts[5]:ital:=opts[6]:  clr:=convert(opts[3],string):cntr:=opts[7]:
 if help=yes then mcprint(
 "format(text,options) changes the font of text in html or latex,
  depending on whether LATEX_=yes.
  options:  
  Size=\"normalsize\",  (use one of \"small\",\"normalsize\",\"large\",
  \"Large\",\"LARGE\",\"huge\", or \"Huge\"
  Color=\"blue\",
  Bold=yes");
 RETURN(NULL) fi:

 if StringTools[Search]("\n",text)>0 then mcprint("replacing \\n's with breaks");
  text:=StringTools[SubstituteAll](text,"\n","_brk_") fi;
  ftable := proc(ft)
   local g,i:
     g:=[[1,"small"],[2,"normalsize"],
[3,"large"],[4,"Large"],
[5,"LARGE"],[6,"huge"],[7,"Huge"]]:
   for i in g do if ft=i[1] or ft=i[2] then RETURN(i) fi od:
   ERROR("Size= must be one of \"small\", \"normalsize\",\"large\",\"Large\",\"LARGE\",\"huge\", or \"Huge\"")
 end:

   if not LATEX_=yes then
 text := cat("lt_font color=\"",clr,"\" size=\"",ftable(size)[1],"\" gt_ ",text," lt_/font gt_");
 if bold=yes then text := cat(" lt_b gt_ ",text," lt_/b gt_ ") fi;
 if undln=yes then text :=cat(" lt_u gt_ ",text," lt_/u gt_ ") fi;
 if ital=yes then text :=cat(" lt_I gt_ ",text," lt_/I gt_ ") fi;
 if cntr=yes then text :=cat(" lt_center gt_ ",text," lt_/center gt_ ") fi;
 else text:=[cat("{\\color{",clr,"}\\",ftable(size)[2]," ",text,"}")];
 if bold=yes then text:=[cat("\\textbf{",op(text),"}")] fi;
if undln=yes then text:=[cat("\\underline{",op(text),"}")] fi;
 if ital=yes then text:=[cat("\\textit{",op(text),"}")] fi;
if ital=yes then text:=[cat("\\begin{center}\n",op(text),"\n\\end{center}\n")] fi;
fi;
text;
 end:

filter7 := proc(infile,path)
local FD,bill,file,line,i,t,n,hd,starttags,stoptags,
TFD,answertags,longline,keep,main;
currentdir(path);
if StringTools[Search](".html",infile)>0 then FD:=infile ; main:=no; else
FD := cat(infile,"1.html"); main:=yes; fi:
#print(FD," being filter7d",main);
if FileTools[IsOpen](FD) then close(FD) fi;
bill := open(FD,READ);
TFD := cat("tmp_",FD);
if FileTools[IsOpen](TFD) then close(TFD) fi;
open(TFD,WRITE);
file:=NULL;
starttags := ["QA_[","QM_[","QN_["]: stoptags:= ["SKIP_"]:
answertags:=["AZ_[","AN_[","AC_[","AR_[","AL_[","AT_[","AS_[","AW_[","AX_[","AK_[","AE_[","AF_[","AI_["];
keep := no;
line := readline(FD);
while line <> 0 do
if StringTools[Search]("H_",line)>0 then keep:=yes fi:
#line := StringTools[Substitute](line,StringTools[Char](13),"");  
if max(op(StringTools[Search](starttags,line)))>0 then  
#line := cat("</p>\n",line,"\n<p>"):
keep:=yes fi;
if StringTools[Search]("T_",line)>0 then  keep:=yes fi;
if max(op(StringTools[Search](stoptags,line)))>0 then
keep:=no fi;

if keep = yes then
longline:= line; line:= readline(FD);

while line<>0 and StringTools[Search]("SKIP_",longline)=0 do
#line := StringTools[Substitute](line,StringTools[Char](13),"");
if StringTools[Search]("SKIP_",line)>0 then
line:= cat("\n</p>\n<p>\n  \n</p>\n<p>\n",line) fi:
longline := cat(longline,"\n",line);
line:=readline(FD);
od;

if main=yes then
longline := StringTools[RegSubs](
"<p align=\"left\">([\n\r]*)</p>"="\\1",longline); fi;

if StringTools[Search]("<math xml",longline)>0 then
longline:= StringTools[RegSubs]
("</p>[\n\r]*<p align=\"center\">([\n\r]*<math)"="\\1",longline);
longline:= StringTools[RegSubs](
"(</math>[\n\r]*)</p>[\n\r]*<p [^>]+>"="\\1",longline);
 fi:
writeline(TFD,cat(longline,"\n</p>\n<p>"));
keep:=no;
#else writeline(TFD,line);
 fi;
line := readline(FD);
od;
close(FD): close(TFD);
open(FD,WRITE); open(TFD,READ);
line := readline(TFD);
while line<>0 do
 writeline(FD,line) ; line := readline(TFD) ;
od:
if mathml=yes then
writeline(TFD,"</p>\n</body>\n</html>") fi;
close(FD);close(TFD);
FileTools[Remove](TFD):
print(cat(FD," filtered"));
"done";
end:

savepic := proc()
local defaults,opts,help,imgformat,height,width,struc,name,path,pltopts,size;
 defaults:= Help=no,Image=gif,Height="300",Width="480",Plotoptions="",Size=large;
 opts:= subs( [op(select(type,[args],`=`)),defaults],[Help,Image,Height,Width,Plotoptions,Size]);
 help:=opts[1]:
 imgformat := opts[2]:
 height:=opts[3]:
 width:=opts[4]:
 pltopts:=opts[5]:
 size:=opts[6]:
 if size=small then height:=200: width:=320:   fi:
  if not StringTools[IsPrefix](",",pltopts) then pltopts:=cat(",",pltopts) fi;
  if help=yes or nargs<2 then
  mcprint("savepic(struc,bill) saves a plotstructure struc with name bill to the currendir, and returns the name of the image for use with addimg.
 NOTE: You will need to set the currentdir to the homework directory,
unless you have used zipit.
Options:
  Image=gif
  Height=300
  Width=480
  Size=large  if Size=small then Height and Width are reset to 200 by 320
  Plotoptions=\"\"  put additional plot options here.
 NOTE: If Image=ps then Plotoptions are set to
 \"width=480pt,height=300pt,shrinkby=.0,noborder,portrait\".  Change as needed");  
  RETURN(NULL)
  fi;
 
  struc:=args[1]: name:=convert(args[2],string): path:=currentdir():
  if not StringTools[IsSuffix](convert(imgformat,string),name) then name:=cat(name,".",convert(imgformat,string)) fi:
  pltopts:=cat("height=",height,",width=",width," ",pltopts):
  if imgformat=ps then if size <> default or (height<>"" and width<>"") then
  pltopts:=cat("width=",width,"pt,height=",height,"pt,shrinkby=.0,noborder,portrait")
else
 pltopts:=cat("shrinkby=.0,noborder,portrait") fi fi;
  plotsetup(imgformat,plotoutput=name,plotoptions=convert(pltopts,symbol)):
  print(struc):
  plotsetup(default):
  convert(name,symbol);
  end:


changepic:=proc(wrksht)
 local bill,line,i,fd,w,d,h,help,opts,defaults,path;
 defaults:=Help=no,Width=200,Height=200,Depth=200,Path=currentdir();
 opts := subs([ op(select(type,[args],`=`)),defaults],
      [Help,Width,Height,Depth,Path]);
 if opts[1]=yes then mcprint(
"changepic(worksheet.mws); will change the dimensions of pictures
 in the worksheet and store the result in tmp_worksheet.mws
 Open the worksheet separately and if the effect is good, save it
 over worksheet.mws (which will need to be closed first)
 options:
 Path=currentdir();  #change this here or issue currentdir(path);
 from the homework worksheet
 Width=200,Height=200,Depth=200  #change these as desired");
 RETURN(NULL) fi:
w:= opts[2];
d:=opts[3]:
h:=opts[4]:
path:=opts[5]:
close(wrksht);
 open(wrksht,READ);
 
fd := cat("tmp_",wrksht);
 close(fd);
 open(fd,WRITE);
 
 line := readline(wrksht);
 while line<>0 do
 #if StringTools[Search]("{GLPLOT",line)>0
 #then line := cat(line,"\n",readline(wrksht)) fi;
 if StringTools[RegMatch]("{GLPLOT([2-3])D [^ ]+ [^ ]+ [^ ]+",line)
then #mcprint(line);  
line:=StringTools[RegSubs]("{GLPLOT([2-3])D [^ ]+ [^ ]+ [^ ]+"=cat("{GLPLOT\\1D ",w," ",w," ",w),line);
  fi:
 
  writeline(fd,line); line:=readline(wrksht);
 od;
 close(fd);close(wrksht);
 mcprint(cat("plots resized to ",w," by ",d," by ",w," in tmp_",wrksht,"."));
 NULL;
 end:

AKhint := proc(label,message)
  local defaults,help,opts;
  defaults:=Help=no;
 opts := subs([ op(select(type,[args],`=`)),defaults],[Help]);
 if opts[1]=yes then mcprint(
 "AKhint(label::string,message::string) formats a button to show a popup hint.");
 RETURN(NULL) fi:
  cat("\nAK_[3;",label,"]\n",message,"\n")
 end:

makeheader := proc(title)
 local multiplicity,base,header,hwflags,files,defaults,opts,titl,i,f,hmwk,fake,p,q,code;
 defaults:=Multiplicity=1,Shuffle=yes,Survey=1,Video=0,Homework=".xhtml",Files="",Help=no,
Fakequestion=yes,Code="";
 opts := subs([ op(select(type,[args],`=`)),defaults],
[Help,Multiplicity,Shuffle,Survey,Video,Files,Homework,Fakequestion,Code]);
 if opts[1]=yes then mcprint(
 "makeheader(title);  generates a title section for a homework.
title is a list whose contents will go to tagit.
Options:
Multiplicity=1  set to n if there are n version of each problem.
Shuffle=no  set to yes if you want the problems to occur in a random order when the Multiplicity>1.
Survey=0  set to n if you want the first n questions to be survey questions with no
question numbers.
Video=\"\"  set to cd if you want the video hint
files to be accessed from a cd on the student machine.
   set to ss if the multiplicity is  n then  in each group of n
 problems if WHS selects the jth one for problem 1 then it selects
 the jth one for every problem.
Fakequestion=yes  set to no to if no fake question is wanted. Note: if a real question
if wanted here, set title to a list of two lists, header and question.
Files=\"\"  Set to a list of pairs [filename,displayname]. these files will be displayed in the text left column.
  Note: you can do the same thing from the zipit line.
Note: If a file is exported from the 5th closed section of \"bill.mws\"
specify the filename \"bill5\".
Code=\"\"  For author-checked answer formats. Set this to the name of a checker .dll which you have in homework directory.");
 RETURN(NULL) fi:
multiplicity:=opts[2];
#if opts[3]=no then base:=-2-opts[4] else base:=opts[4]+1 fi;
if opts[3]=no then base:=-1-opts[4] else base:=opts[4] fi;  
if opts[5]=cd then hwflags:=1 else hwflags:=0 fi;
if (opts[5]=ss) then hwflags:=2: fi:
 if (opts[5]=cdss) then hwflags:=3: fi:
hmwk:=opts[7]:
if opts[6]="" then files:="" else
  if  type(opts[6],listlist) then
files := NULL:
for f in opts[6] do
if not StringTools[IsSuffix](hmkw,f[1]) and StringTools[Search]("poId",f[1])=0
then f[1]:= cat(f[1],hmwk)  fi ;
files:=files,f
od: files := [files]:   
files:=cat(";",StringTools[Join]([seq(StringTools[Join]
(files[i],","),i=1..nops(files))],":"))
 else ERROR("Files must be a list of pairs") fi:
 fi;
if not type(title,list) then titl := [title] else titl:=title fi:
 mcprint(cat("H","_[",multiplicity,";",opts[9],";",base,";;",hwflags,files,"]\n\n\SKIP","_\n\n"));
if opts[8]=yes then
 if type(titl[1],list) then
 p:= titl[1];q:=titl[2];
#if nops(titl)>1 then q:=[seq(titl[i],i=2..-1)]; print(q) else q:= [""] fi;
 else p := titl: q:=[""]
fi:
 tagit(hidden=survey, pretext=p, op(q))
else
 mcprint("T","_\n",op(titl),cat("\n\nSKIP","_\n")) fi
end:

##vbutbox
vbutbox := proc(Lst)
  local af,i,j,k,p,id,defaults,opts,help,m,mtmp,button,q,bks,lst;
  defaults:=Help=no,Shuffle=yes,Id=-rand(1..10000)(),Rightone=1,Button="radio",Breaks=no;
 opts := subs([ op(select(type,[args],`=`)),defaults],[Help,Shuffle,Id,Rightone,Button,Breaks]);
  help:=opts[1]:
  p:=opts[2]:
  id :=opts[3]:
  m:=opts[4]:
  button:=opts[5]:
  bks:=opts[6]:
  
  if button="radio" then button:="R" else button:="Q" fi:
if m<>0 then lst := Lst else
  lst:=NULL:  m := NULL:
  for i from 1 to nops(Lst) do
  if not type(Lst[i],list) or not member(Lst[i][1],{0,1}) then ERROR("When Rightone=0, you must mark the correct alternatives with 1 and incorrect one with 0.") fi;
  if Lst[i][1]=1 then m := m,i fi;
  lst := lst,[seq(Lst[i][j],j=2..nops(Lst[i]))];
  od;
  lst:=[lst];
  if button="Q" then m := [m]; fi;   
fi;

  if help=yes then mcprint(
"vbutbox(lst::listlist) constructs a group of vertical radio button or checkbox
 alternatives with the same identifier (Id below).
 The first alternative is assumed the correct one, unless modified by the Rightone= option.
 Options:
 Help=no
 Button=\"radio\"  change to \"checkbox\" for checkbox alternatives.
 Breaks=no   Change to yes to put alternatives on different lines.
 Rightone=1   Change to the correct alternative as needed.  Note: if Button=\"checkbox\"
              set Rightone=the list of correct alternatives.  
 Shuffle=yes  Change to no to turn off shuffling.
             Or insert a permutation of nops(lst) to shuffle the positions
 Id = -rand(1..10000)()   If you want a particular identifier, use a positive
  integer if you want WHS to shuffle it, otherwise use a negative integer");
 RETURN(NULL) fi:
if p=no then p:=[seq(i,i=1..nops(lst))] elif
 p=yes then p:=combinat[randperm]([seq(i,i=1..nops(lst))]) else
     if not type(p,list) or nops(p)<>nops(lst) or max(op(p))<>nops(lst) then
  ERROR("Shuffle must be a permutation of 1 thru no. of alternatives.") fi fi;
  mcprint(p);
  if button="R" then mtmp:=-1:
  for i from 1 to nops(p) do
  if p[i]=m then mtmp:=i; ;fi od: if mtmp>-1 then m := mtmp else ERROR("Need a Rightone=") fi
  elif button="Q" then
  q := "";
  for i from 1 to nops(p) do
  if member(p[i],{op(m)}) then q:=cat(q,";",convert(i,string)) else   q := cat(q,";")  fi;
  od:
   m := q;
  fi;    
  af := cat("A",button,"_[",convert(id,string),";1]");
  k:=NULL;
  for i from 1 to nops(lst)-1 do
  if (type(lst[p[i]][1],function) and op(0,lst[p[i]][1])=PLOT) or type(lst[p[i]][1],string) then
  k:=k,af,op(lst[p[i]]); else k:=k,af,"",op(lst[p[i]]) fi;
 if not ((type(lst[p[i]][-1],function) and op(0,lst[p[i]][-1])=PLOT) or type(lst[p[i]][-1],string)) then
  k:=op([k,""]) fi;
  if bks=yes then k:=k,Brak() fi:

 od:
 if button="R" then
 if (type(lst[p[-1]][1],function) and op(0,lst[p[-1]][1])=PLOT) or type(lst[p[-1]][1],string) then
  k:=k,_Ar([id,m]),op(lst[p[-1]])  else k:=k,_Ar([id,m]),"",op(lst[p[-1]]) fi;
if not((type(lst[p[-1]][-1],function) and op(0,lst[p[-1]][-1])=PLOT) or type(lst[p[-1]][-1],string)) then
   k:=op([k,""]) fi;
else
if (type(lst[p[-1]][1],function) and op(0,lst[p[-1]][1])=PLOT) or type(lst[p[-1]][1],string) then
  k:=k,_Aq([id,m]),op(lst[p[-1]])  else k:=k,_Aq([id,m]),"",op(lst[p[-1]]) fi;
if not((type(lst[p[-1]][-1],function) and op(0,lst[p[-1]][-1])=PLOT) or type(lst[p[-1]][-1],string)) then
   k:=op([k,""]) fi;
fi;
  k;  
   end:
##end vbutbox

##tbuttons
tbuttons := proc(Lst)
  local af,i,j,k,p,id,defaults,opts,help,m,mtmp,nc,c,tabopts,cellopts,co,button,q,lst,labels,labels1,labels2;
    if member(args[1],{Help,Help=yes,"Help"}) then mcprint(
"tbuttons(lst::listlist) constructs an array of radio button (default) or checkbox  
 alternatives with the same identifier (Id below).
 The first alternative is assumed the correct one, unless modified appropriately
 with the Rightone= option.
 Options:
 Help=no
 Button=\"radio\"  change to Button=\"checkbox\" for an array of checkbox alternatives
 Rightone=1   For Button=\"radio\" change to the correct alternative as needed.
              For Button=\"checkbox\" change to a list of correct alternatives
 Numcols=1   Change to the number of columns you want.
 Shuffle=yes  Change to no to turn off shuffling.  
              Or insert a permutation of nops(lst) to shuffle the positions
              Note: For problem replication purposes, if is recommended that you
              generate the permutation of the alternatives using getparams
 Id = -rand(1..10000)()   If you want a particular identifier, use a positive
  integer if you want WHS to shuffle it, otherwise use a negative integer
 Labels=\"\"  Replace by Labels=1 to get [\"A) \",\"B) \", etc] or Labels=2 to get red letter labels.
              or Labels=[any list of strings]
 Tableopts=\"\"  replace with
an appropriate format string
 Cellopts=\"\"   replace with a format string for all cells or a list of
 pairs [n,string], where n is the cell number to be formatted with string.");
 RETURN(NULL) fi:

labels2:=[seq(cat("lt_font color=\"red\" gt_lt_b gt_",convert([i+65],'bytes'),") lt_/b gt_ lt_/font gt_ "),i=0..25)]:
labels1:=[seq(cat(convert([i+65],'bytes'),") "),i=0..25)]:  defaults:=Shuffle=yes,Id=-rand(1..10000)(),Rightone=1,Numcols=1,
Tableopts="",Cellopts="",Button="radio",Labels="";
 opts := subs([ op(select(type,[args],`=`)),defaults],[Shuffle,Id,Rightone,Numcols,Tableopts,Cellopts,Button,Labels]);
  p:=opts[1]:
  id :=opts[2]:
  m:=opts[3]:
  nc :=opts[4]:
  tabopts:=opts[5]:
  cellopts:=opts[6]:
  button:=opts[7]:
  labels:=opts[8]: if type(labels,string) then labels:=[seq(labels,i=1..nops(Lst))]
                   elif labels=1 then labels:=labels1
                   elif labels=2 then labels:=labels2 fi;
  if member(button,{"round","R","radio"}) then button:="R"
  elif member(button,{"square","Q","checkbox"}) then button:="Q" else
   ERROR("Button=\"radio\"  or Button=\"checkbox\"") fi:

  if m<>0 then lst := Lst else
  lst:=NULL:  m := NULL:
  for i from 1 to nops(Lst) do
  if not type(Lst[i],list) or not member(Lst[i][1],{0,1}) then ERROR("When Rightone=0, you must mark the correct alternatives with 1 and incorrect ones with 0.") fi;
  if Lst[i][1]=1 then m := m,i fi;
  lst := lst,[seq(Lst[i][j],j=2..nops(Lst[i]))];
  od;
  lst:=[lst];
  if button="Q" then m := [m]; fi;   
fi;


  if type(cellopts,string) then cellopts:=[seq(cellopts ,i=1..nops(lst))]
  elif type(cellopts,list) then co:=NULL;j:=1;
  for i from 1 to nops(lst) do
 
  if j <= nops(cellopts) and cellopts[j][1]=i then co:=co,cellopts[j][2];
  j:=j+1 else co:=co,"" fi od;
  cellopts:=[co];
  else ERROR("Check Help for syntax of Cellopts");
  fi;

if p=no then p:=[seq(i,i=1..nops(lst))]
 elif p=yes then p:=combinat[randperm]([seq(i,i=1..nops(lst))])
else if not type(p,list) or nops(p)<>nops(lst) or max(op(p))<>nops(lst) then
   error "Shuffle must be a permutation of 1 thru no. of alternatives." fi fi;
 # mcprint(p);

if button="R" then mtmp:=-1:
  for i from 1 to nops(p) do
  if p[i]=m then mtmp:=i fi od:
  if mtmp>-1 then m := mtmp else ERROR("Need a Rightone=") fi

  elif button="Q" then q := "";
  for i from 1 to nops(p) do
  if member(p[i],{op(m)}) then q:=cat(q,";",convert(i,string))
       else   q := cat(q,";")  fi;
  od:
   m := q;
fi;
 
#adding labels to tbuttons 1/09
   
  af := cat("A",button,"_[",convert(id,string),";1]");
  k:=[cat("lt_table ",tabopts," gt_\nlt_tr gt_\nlt_td ",cellopts[p[1]]," gt_")];
 c := 1;
  for i from 1 to nops(lst)-1 do
  if (type(lst[p[i]][1],function) and op(0,lst[p[i]][1])=PLOT) or type(lst[p[i]][1],string) then
  k:=k,af,labels[i],op(lst[p[i]])  else
  k:=k,af,labels[i],op(lst[p[i]])
  fi;
 if not ((type(lst[p[i]][-1],function) and op(0,lst[p[i]][-1])=PLOT) or type(lst[p[i]][-1],string)) then
  k:=op([k,""]) fi;
k := k,["lt_/td gt_"]:
c := c+1;
if c > nc then  k:= k,["lt_/tr gt_\nlt_tr gt_"];
 c := 1; fi:
k:=k,[cat("lt_td ",cellopts[p[i+1]]," gt_")];

 od:
 if button="R" then
 if (type(lst[p[-1]][1],function) and op(0,lst[p[-1]][1])=PLOT) or type(lst[p[-1]][1],string) then    k:=k,_Ar([id,m]),labels[nops(p)],op(lst[p[-1]])  else k:=k,_Ar([id,m]),labels[nops(p)],op(lst[p[-1]]) fi;
 else
 if (type(lst[p[-1]][1],function) and op(0,lst[p[-1]][1])=PLOT) or type(lst[p[-1]][1],string) then    k:=k,_Aq([id,m]),labels[nops(p)],op(lst[p[-1]])  else k:=k,_Aq([id,m]),labels[nops(p)],op(lst[p[-1]]) fi;
 fi;
if not((type(lst[p[-1]][-1],function) and op(0,lst[p[-1]][-1])=PLOT) or type(lst[p[-1]][-1],string)) then
 k:=op([k,""]) fi;
#c := c+1;
 k:= k,["lt_/td gt_\nlt_/tr gt_\nlt_/table gt_"];


  k;  
   end:
##end tbuttons



#THE FOLLOWING MUST BE THE LAST IN THIS EXECUTION GROUP
###mctools
mctools:=proc()
 local txt:
 mcprint("MCtools, version ",ver,".");
 if (args=NULL  or nargs>1) then
  mcprint(" "):
  mcprint("Current choices are ",MCTOOLS_,".");
  mcprint(" "):
  mcprint("\"mctools(X)\" gives syntax and defaults for \"X\""):
  mcprint(" "):
  RETURN():
 fi:
 txt:=args[1]:
 if
 txt=archiveit then mcprint("See archiveit(Help=yes); for details")
 elif
  txt =PARAMS then mcprint("PARAMS(Defaults,Args)"):
 elif txt =PT   then
  mcprint("PT(Location,txt,fontsize=16,clr=black) ");
 elif txt =colors then
  mcprint(" colors()  to see colors  use \"colors(showthem = yes)\".");
 elif txt = DL then
  mcprint("DL(A,B,thknss=2,styl=1,clr=blue,leftshrinkfactor=0,
    rightshrinkfactor=0,hashnum=3,hashlength=.3,hashspacing=.1,
    hashlocation=.5)  ");
 elif txt = DV then   
  mcprint("DV(tail=[0,0],head=[2,2],name=``,Length=1,angle=15,
    fudge=[.1,.1],type=\"V\") draws an arrowhead with tines at an angle of
    15 degrees with the shaft and of length 1. If there is a name,
    it is put next the the head with an offset of fudge=[.1,.1]. If <> V
    then the arrowhead is solid.");
 elif  txt =GP then
  mcprint("GP(llcorner=[-5,-5], width=10, height=10,
    resolution=2, tickmarkfont=12, axescolor=red) ");
 elif  txt=GP2 then
  mcprint("GP2(llhc  = [-5,-5],width=10,height=10,xres=1,yres=1,
    clrs=[black,black],xlabl=`x`, ylabl=`y`,TMfont=NTM)");
 elif txt = GP3 then
   mcprint("GP3(llhc= [0,0,0],width=10,height=10,depth= 10, xres=10/3,
     yres=10/3, zres = 10/3, clrs =[black,red,blue],xlabl=`x`, ylabl=`y`,
     zlabl = `z`, TMfont=NTM)");
 elif txt = MM then
   mcprint("MM(partslist=f,tinter=[1,2],numframes=5,speed=1)");
 elif  txt =PP then
   mcprint("PP(location,radius, clr=blue,scalefactor=1) ");
 elif  txt =ARRW then  
   mcprint("ARRW(tail=[0,0],head=[1,2],headwidth=3,headlength=4,
     shaftthickness=.03,clr=green,arrowtype=`DH`,doublearrowtxt=\"texthere\",
     fontsize=16,txtclr=black,dhgap=1/3) ");
 elif txt = CARR then  
  mcprint("CARR(pts=[[0,0,0],[1,0,0],[1,1,0],[1,1,1]],clr=gray,rad=.02,
    hdlen=.2,hdwid=.1,spltp=[cubic,cubic,cubic])\nalso
    CARR(pts=[[0,0],[1,0],[1.3,1],[1,2]])  gives a 2-d curvilinear arrow.");
 elif txt =PC then
  mcprint("PC(center,radius, thknss=2, styl=1, clr=black,scalefactor=1)  ");
 elif txt = PA then
  mcprint("PA(center,radius,theta1,theta2, thknss=3,
    styl=1, clr=black,scalefactor=1)  ");
 elif txt = roundto then
  mcprint("roundto(x,places=3,leadzero=yes)");
 elif txt = roundit then
  mcprint("Use roundit(Help=yes) to see usage. ");
 elif txt =hashang then
  mcprint("hashang(A,B,C,radius=1,numhashes=3,hashspacing=.1,
    withhead=`NO`,headthickness=1,headlength=1,clr=black,reversehead=`NO`,
    otherway=`NO`,fliphead=`NO`) ")
 elif txt = RANDANS then   
  mcprint("RANDANS(ANSWERS,rightans=1,choices=letters,
    answerstyle=mulchoice_labeled)")
 elif txt=vbutbox then mcprint("see vbuttons(Help=yes)")
 elif txt=tbuttons then mcprint("see tbuttons(Help=yes)")
 elif txt = generator or txt=tagit then
  mcprint("tagit(strings,expressions,lists,answer formats,option equations)
    strings are mcprinted, expressions are printed,  the ops of lists are mcprinted,
    answer formats produce answer tags:   They are
    _AC(answer,options) where answer is the correct answer to the question,
    options are option equations, and aftertext are strings, lists and expressions
    to be put into an aftertext option. Two options which are commonly set are
    txtboxsize and precision. The defaults for txtboxsize and precision
    are 5 and .05.
    _AZ([initstring,rightanswerstring]) where initstring is the x string in
     az_[x] and rightanswerstring goes into the QMline (see author documentation)
    _AN(answer) where answer must be a numeric string  
    _AW(answers)  where answers is a list of possible spellings of the word,
    or a string of #-separated possible spellings of the word.
    _AS(answers) This is a multiple choice answer format.    
    producing a scroll box with alternatives
    _AS(answers) where answers is a list of alternative answers with
    the correct answer first.
    _TP() Use this if you want to end a problem part after an answer
    description has been specified.   Any options given before the problem
    terminator are applied to that part.  Any strings and expression are put
    in the aftertext option to that part.
    _AF(f,options)   where f is an algebraic expression with one variable,
    and options are txtboxsize, precision, and funstuff.  The defaults are txtboxsize=15, precision=.05, and funstuff=[x,6,.1,1].
    _AI(f,options)   just like _AF, that   WHS counts it as correct if it
    differs by a constant within a specified error set by the precision option.  
    It is most often used to test answers to antidifferentiation problems.
    _AE(f,options)  just like _AF, except that more than one varible is permitted.
    _AL(answers) where answers is a list of alternative answers with the
    correct answer first. a row of radio buttons is produced
    _AR(answers) like _AL, except that the radio buttons occur vertically
    _ALlabels(answers)  just like AL execpt the alternative are labelled
    and put above the row of radio buttons
    _AB(answers)  like AL except that more than one answer can be right.
    right answers in   the list of answers are enclosed in square brackets.
    _ABlabels(answers) like AB except that the alternatives are labelled
    and put above the row of checkboxes.
    _AT(list of lists)  creates a tables of  AC boxes.   entries which are
    enclosed in square brackets are replaced with AC boxes.
    _ATcross(list of lists)  creates a table of AC, AF, AI, AE, AW, and AS boxes.
    each entry is printed or mcprinted unless it is a list [answers]
     and answers is written in the form expected by AC, AF, AI, AE, AW or AS.

    The option equations are
    standards=\"\"  set to a comma separated list of labels identifying a
    list of standards tested (from some list of course standards or state-mandated
    standards)
    prextext=NULL, set to a string or list to put text before question
    brks=0, for no breaks, 1 for break after, 2 for break before, 3 for break
    before and after the text preceding the answer box.  To suppress the
    header tag, use brks=4
    precision=`.05`,  measures error in response, used with AC, AF, AI, AE, AT,
    ATspread, ATcross  
    txtboxsize=8,   number of spaces in the answer box  used with AC, AF, AI, AE,
    AT, ATspread, ATcross_  
    randomize=no, set to yes if you want the alternatives scrambled..
    matsize=[1,5], sets the array the alternatives are shown in _ALlabels
    and _ABlabels
    Alabels=[A,B,C,D,E,F,G,H], sets the labels used in _ALlabels and _ABlabels
    Flabels=\"color=red\",  sets the label color in _ALlabels and _ABlabels
    hidden=no  set to yes to hide the answer on feedback sheet.
    inline=no,  set to [yes] for one line questions;[yes,opts1] opts1 is list
    of options to Lineit; [yes,opts1,opts2] opts2 is list of options to Lineit
    (used in aftertext)")
 elif txt=Axes then
  mcprint("Axes(xrng=[-5,10],yrng=[-5,10],clrs=[blue,blue],thkns=2,head=[.5,.2])")
 elif txt=zipit then
  mcprint("zipit(\"sample\",\"full path to zip file directory\"); where
   sample.mws is the name of your source worksheet.  A modified verison of the
   file sample1.html is written to samplewhs.html.  Then ordinarily
   a zipfile named samplewhs.zip is created in the zip file directory, which can
   then to be installed on mathclass.  By setting the option Zip=no, the creation
   of the zipfile is bypassed.
   Other Options
   Zname = \"stuff\", the name for your zipfile.  By default it it set to    
   \"samplewhs\", if sample.mws is the name of your source worksheet.
   Important! the name of your zipfile must also be the name of your WHS homework.
   Magic=76 is the number that occurs just after Homes in the url that you can
   read while your mathclass homework is loading.  Set this if you have an
   addsectionhint or  
   an addvlink in a problem.
   Target=\"Content\", set this to no if you want hints to open in the same window.
   Archive=no  set to yes to automatically save MCtools and latextools to
   mclatools.lib in homework directory.  
   Set to MCtools if only MCtools is to be saved or no if nothing is saved
   PathtoZip = \"\", set this to the path to your Info zip, if it is not on the
   system. For example if your copy of zip is on a floppy in the A drive set
   PathtoZip=\"A://\"
   Mathml = no,   set this to yes if you are exporting to html with mathml on
   Maple 9.5. In this case Zname is set to samplekde unless you set Zname.
   Files={}  set this to [[\"bill5\",\"Title 1\"],[\"bill8\",\"Title 2\"]] if the 5th and 8th closed sections
   of bill are to be displayed as text on the left.
Note: When Mathml=yes, use \"bill5.xhtml\" in place of \"bill5\".")
 elif txt=zipp then
  mcprint("zipp(\"name\",\"path\") where name is the name of the htm or html
   file you want for the webpage and path is the path to the directory containing
   that htm or html file.  Everything in that directory is zipped up in a zipfile
   name.zip and placed at that level of the source directory. If an optional 3rd
   argument is given it is assumed to be the path to zip (including the name of
   the zip application)")
 elif txt=ah_ then
  mcprint("ah_(n), where n is 0,1,2, or 3. then tagit prints an answer header
   AH_[n] which puts returns before or after the answer formats  numberbox,
   wordbox, selection, functionbox, integralbox, or mfunctionbox.  
   0 means no break before and after the format, 1 means a break after,
   2 means a break before, and 3 means a break before and after.")
 elif txt=av_ then
  mcprint("av_(n,file,message), where n is 0,1,2, or 3, file is the name of
   an audio or video clip, and message is to be put on the button to play the clip.
   \nNote: If the n is omitted, it is set to n=3.  If the message is omitted,
   it is set to Click here.")
 elif txt=addlink then
  mcprint("type addlink(Help=yes) to get details.
   This word is written to be used in the problem=, pretext=, and aftertext=  
   environments, but can be mcprinted outside those environments.")
elif txt=addimg then
mcprint("addimg(\"filename\")  puts the image (gif or jpg for sure) into the homework
  if the image is in the homework folder.  You can also give the url to
 an image. Note: a second argument is optional. It is a
string of img options with values escape quoted: \"ALT=\\\"flower picture\\\" WIDTH=\\\"100\\\"\"
Note2: if argument 2 is either latex or [latex,\"hfill\"] or [latex,[\"\\hspace{3in}\",\"width=240,height=329\"]] then addimg puts in tex.")
 elif txt=addsectionhint then
  mcprint("'addsectionhint'(message,sectionmaterial), where title is the clickable
   message, and sectionmaterial is a list of strings, lists, and expressions. This
   word is written to be used in the problem=, pretext=, and aftertext=
   environments,     but can be mcprinted outside those environments.
   Note: If you create a sectionhint by hand, put a hard return after the BEGINHINT line.")
 elif txt=tableit then
  mcprint("tableit(list,cols), where list is a list of things to be put in a table
   with cols columns. tableit is written to be used in problem= or in
   pretext= (or in aftertext= )")
 elif txt=Maketable or txt=maketable then
  mcprint("maketable(list), where list is either a list, a matrix or a
   list of lists.
   Options:  
(1) columns=6, the number of columns in the table (active only
   if list is a list
(2) cellfmts=[\"\"], a one element list or a list or a
   matrix or a list of lists of format instructions for the various cells
(3) rowfmts=[\"\"], a one element list or a list of format instructions
   for the rows
(4) tablefmts=\"border = \"1\"\" (5) immediate=no, set this to
   yes when used outside of the text options of tagit.")
 elif txt=mcpiecewise then
  mcprint("\"mcpiecewise\",[p], where p is an expression sequence of expressions,   
   equations or lists whose first term is an expression or equation and whose second
   term is an inequality, prints up a nice piecewise defined function.  Note the
   unusual syntax. The execution of mcpiecewise(p) is actually done at the end of
   tagit.")
 elif txt=fill then
  mcprint("fill(f,g,a,b)[1]  colors the region between the graphs of the functions
   f and g.  fill(f,g,a,b)[2]  gives an approximation of the area based on the
   specified partition and rule.
   Options:  
   (1)  Color=[yellow,black,black] the color of the region and the graphs
   of f and g,
   (2)  Style=patchnogrid   the polygons making up the region have no
   boundary,
   (3)  Thickness=[1,1]  the thicknesses of the graphs of f and g respectively.
   (4)  Numpts=49  the number of polygons the region is broken into.
   (5)  partition=regular -- the interval [a,b] is divided into Numpts
   subintervals of equal width, otherwise set partition=[s] where is an
   increasing sequence of numbers strictly between a and b.
   (6)  rule=left/right/mid sets the 'marks' as the left hand endpoints/right
   hand endpoints/midpoints of each subinterval, else if rule=trap the polygons
   are trapezoids,
   (7) marks=[m], where m is a sequence of 'marks', one from each subinterval
   of the partition.
   this only needs to be set when partition=[s] and rule lessthan greater left
   right mid or trap")
 elif txt=changepic then
  mcprint("changepic(Help=yes); will give the syntax")
 elif txt=format then
  mcprint("format(Help=yes); will give the syntax")
elif txt=ltagit then
  mcprint("ltagit(Help=yes); will give the syntax")
elif txt=stagit then
  mcprint("stagit(Help=yes); will give the syntax")
 elif txt=Standardize then
 mcprint(
"Set Standardize:=[request];  a list whose contents are acceptable
 to stagit. See mctools(stagit). If Standardize is not a list then no followup survey
 question is generated.")
 elif txt=AKhint then
  mcprint("AKhint(Help=yes); will give the syntax")
elif txt=makeheader then
  mcprint("makeheader(Help=yes); will give the syntax")
 elif txt=Line then
  mcprint("Line(expression sequence), where expression sequence is a list of
   strings, mathexpressions, pictures, and answer formats to be put on a single
   line. It is your responsibility to decide whether the line is not too long.
   Any options to an answer format must be put in the format.
   Note: To adjust the vertical alignment in individual cells, use the
   cellfmt= option (see mctools(Lineit) for details.")
 elif txt=Lineit then
  mcprint("Lineit(list), where list is a list of things to be put in a single
   line. Lineit is written to be used in problem= or in pretext= (or in aftertext= ).
   Lineit can include answer formats.
   Options: (1) tops, a string containing the table options:  e.g.,
   tops=\"border = \"1\"\"
   (2) cellfmts=[2,2,2,2,2,2,2,2,2]   use these to adjust the vertical alignment
   of each cell of the line. Use 1, 2, or 3 to put the cell contents at the top,
   middle, or bottom of the cell.
   (3) startable=yes, set is to no if you are in the middle of a table,
   (4) endtable=yes, set this to no if you don't want the table to end quite yet,
   (5) newrow=no, set this to yes to start a new row,
   (6) maxcols=10, set this higher at your own risk")
 elif txt=mcprint then
  mcprint("mcprint(strings,expressions)  converts all the inputs to a single
   string and lprints it without the quotes.")
 elif txt=symbolize then
  mcprint("Several usages:
   1.  symbolize(value) where value is an integer, float or fraction. Returns value
   converted to a symbol (negative integers have parentheses about them; the top and
   bottom of the fraction are converted separately)
   2.  symbolize(value) where value is an equation whose rhs is an integer, float
   or fraction. Returns value converted to a symbol (negative integers have
   parentheses about them; the top and bottom of the fraction are converted separately)
   3.  symbolize(value) where value is a list of values or a set of values.
   Returns a list or set of symbolized values
   4.  symbolize(f,value) where value is a list of values and f is a function with
   at least that many arguments:  the list is symbolized and the function is
   evaluated at those values
   5.  symbolize(value,f) where value is a list of equations and f is an expression:  
   the list is symbolized and the values substituted into the expression")
elif txt=savepic then mcprint("savepic(struc,bill)  to save a plotstucture struc to the currentdir path with name bill.  See savepic(Help=yes) for options")
elif txt=`&=` then mcprint("a &= range assigns to a a value randomly chosen according to how
range is specified. It is equivalent to assign([a,range]).
  See assignvals(Help=yes) for details.")
elif txt=`&==` then mcprint("'a' &== range assigns to 'a' the function which randomly choses a value according to how range is specified.  
See assignvals(Help=yes) for details on range specification.
Note: can be used with procedures which have an unnamed procedure as an argument.
'k' & (1,(10..20)): linalg[randmatrix](3,4,()->k());")
elif txt=assignvals then mcprint("assignvals(lst) assigns values to variables chosen randomly according to a range specification.  See assignvals(Help=yes) for details.")
 else
  mcprint("Sorry that's not in the list.");
  mctools();  
 fi:

end:
###end mctools

end module;

>    with(MCtools);

>    MCdefaults();

>    ##begin latextools

>    latextools := module()
local  bigcolorlist,cc,correctcc,
       ABBREVS,ABBREVSAMS,AMSMACROS,DOCSTYLE,DOCSTYLEAMS,FONTS,
       LENGTHS,MACROS,PKGS,PKGSAMS,PSTYLE,PREAMBLE,PSTYLEAMS,
       SSFONTS,VERSION,
       colorfun,dupindex,escape,getstyles,rootify,getitout;
global LNUM_,CHECK_,MARK_,PARA_,SECT_,EXCHG_,TEXT_,LATEX_,PREAMBLEAMS;
export LAdefaults,cover,extractlatex,fixeps,fixalleps,getnums,glosub,
       htmlit,htmlrootwork,lagit,latexit,latextoolshelp,latexwhs,
       makexam,mkhtmlindex,mprint,mwsit,mwsrootwork,mwswrite,mwszip,
       rootwork,showgs,show_sections,tprint,unmwsit,
       vers,whslatex,wellformed?,xprint,lxprint,zipthese,graphic,
       ansbox,latrix,multichoice,detrix,parbox,minipage,
       picps,formatit,fracit,Fracit;
options package;

VERSION := "2/5/2009":
print("");print("");
lprint("EXECUTE latextoolshelp(); FOR Startup Help.");
print(""); print("");
LAdefaults:=proc()
global LNUM_,CHECK_,MARK_,PARA_,SECT_,EXCHG_,TEXT_;
MARK_ := "MARK":
PARA_:="PARA":
TEXT_:="TEXT":
EXCHG_:="EXCHG":
SECT_:="SECT":
VERSION;
end;

##latrix
latrix := proc(lst)
 local mat,i,j,fmt,pos,defaults,opts,help,rowsep,hline;
 defaults:=Help=no,Position="",Format="",RowSep=1,Hline="": opts:=subs([op(select(type,[args],`=`)),defaults],[Help,Position,Format,RowSep,Hline]);
 help:=opts[1]:
 if help=yes then mcprint("latrix(lst)  prints a table for use with latextools.  
Options:
Position=\"[c]\"  places the table on the line of text.  t=top down, b=bottom up
   default is to center the table on the line.
Format=\"ccccc\" is the formatting string: l is left, r is right, | is vertical line
RowSep=1 Set to 2 for double space, 1.5 for 1 and a half space, etc
Hline=off  set to on to put horizontal lines in."); RETURN(NULL) fi;
 pos := opts[2]:
 if not StringTools[IsPrefix]("[",pos) then pos := cat("[",pos,"]") fi;
 rowsep :=opts[4];
 hline:=opts[5];
 if hline=on then hline:="\\hline" fi;
 if opts[3]<>"" then fmt := opts[3] else
  fmt := cat(seq("c",i=1..nops(lst[1])-1),"c") fi;
  mat := cat("\\begin{tabular}",pos,"{",fmt,"}",hline,"\n");
  for i from 1 to nops(lst) do
  if type(lst[i],string) then mat:= cat(mat,lst[i]); next fi;
  for j from 1 to nops(lst[i]) do
  if not type(lst[i][j],string) then
  mat:= cat(mat,"$",`latex/print`(lst[i][j]),"$") else
  mat:= cat(mat,lst[i][j]) fi;
  if j < nops(lst[i]) then mat:= cat(mat," & ") else mat:=cat(mat," \\\\",hline,"\n") fi:
  od od;
mat := cat(mat,"\\end{tabular}\n");
 if rowsep<>1 then
 cat("\n\\renewcommand{\\arraystretch}{",convert(rowsep,string),"}\n",mat,
"\\renewcommand{\\arraystretch}{",convert(evalf(1/rowsep,6),string),"}\n") else mat fi;
end:


Fracit:=proc(expr)
  local e,n,d;
  if nargs =0 or arg[1]=Help then return("fracit(expr) (or Fracit(expr)) returns a  string formatting the fraction expr in latex (displaystyle).  
If expr is in a list then dollar signs are inserted.
Note: If you don't want the fraction simplified to lowest
terms, put in the numerator and denominator separately (as 2 arguments).  These can be entered as strings.
Note: fracit(expr) works just like Fracit, except not in displaystyle.") fi;
if nargs=2 then n:=args[1]: d:=args[2]: fi;
if nargs=1 and not type(expr,list) then
 e := simplify(expr): n:=numer(e): d:=denom(e): fi;
if nargs=1 and type(expr,list)  then if nops(expr)=1 then
 e := simplify(op(expr)): n:=numer(e): d:=denom(e):
  else n:=expr[1]: d:=expr[2] fi;
 fi;  
if not type(n,string) then n:=`latex/print`(n) fi;
if not type(d,string) and d <> 1 then d := `latex/print`(d) fi:  
if type(expr,list) then
      if d=1  then cat("$",n,"$")  else cat("$\\Frac{",n,"}{",d,"}$") fi
else if d=1  then n  else cat("\\Frac{",n,"}{",d,"}") fi
 fi;   
end:
fracit:=proc()
 local expr;
 if nargs=0 then expr:=NULL else expr:=args fi;
 StringTools[Substitute](Fracit(expr),"\\Frac","\\frac") end:

formatit:=proc()
  local name,lst;
  if nargs<> 2 then mprint("formatit(name,list) returns \"\\name{list[1]}{list[2]}...\"
 formatit(name,string) returns \"\\name string\""); return NULL fi;
  name:=args[1]:lst:=args[2]:
  if type(lst,string) then
  cat("\\",convert(name,string),lst) else
  cat("\\",convert(name,string),cat(seq(op(["{",convert(lst[i],string),"}"]),i=1..nops(lst)))) fi;
end:

multichoice:=proc(Lst)
 local mat,row,i,j,labels,cols,defaults,opts,help,Lisst,cnt,rowsep,out,scram,key,lst,correct,cell,p,q;
 defaults:=Help=no,Cols=1,Labels=["\\textbf{A)} ","\\textbf{B)} ","\\textbf{C)} ",
"\\textbf{D)} ","\\textbf{E)} "],List=no,Rowsep=2,Scramble=yes,Correct=1:
opts:=subs([op(select(type,[args],`=`)),defaults],[Help,Cols,Labels,List,Rowsep,Scramble,Correct]);
 help:=opts[1]:
 if help=yes then
mcprint("multichoice(lst)  returns 3 things:
  1) a string which typesets the alternatives in a table
  2) the correct answer typeset for the key and
  3) a list giving the order in which the alternatives are shown.  
Options:
Cols=1 change to a larger integer if more columns are wanted.
List = no  change to yes to put brackets around the first output.  
Labels=[\"A\", etc]  format these as desired
Rowsep=2  doublespaced change to 1.5 for 1 and a half space, etc
Scramble=yes  change to a permutation of 1 thru number of alternatives to impose an ordering.
Correct=1  gives the index of the correct alternative"); RETURN(NULL);fi;
cols:=opts[2]:
labels:=opts[3]:
Lisst:=opts[4]:
rowsep:=opts[5]:
scram:= opts[6]:
correct := opts[7]:
lst := Lst;
if nops(Lst)>nops({op(Lst)}) then mcprint(Lst);
  error "At least two alternatives are the same." fi;
if scram=yes then
p := combinat[randperm]([seq(i,i=1..nops(lst))]) elif
type(scram,list) and nops(scram)=nops(lst) then p := scram else
p:=[seq(i,i=1..nops(lst))] fi;
q := NULL:
for i from 1 to nops(lst) do for j from 1 to nops(lst) do
if p[j]=i then q := q,j fi  od od:
lst:=[seq(lst[p[i]],i=1..nops(lst))]:
mat := NULL;cnt:=0;row:=NULL;key:="":
for i from 1 to nops(lst) do
cnt := cnt+1;
if not type(lst[i],string) then
cell :=cat(labels[i],"$",`latex/print`(lst[i]),"$")
else
cell :=cat(labels[i],lst[i]) fi;
if q[correct]=i then key := cell fi:
row := row,cell;
if cnt=cols or i = nops(lst) then row := [row];
mat:= mat,row; row := NULL; cnt:= 0 fi;
od:
out := latrix([mat],Position="[c]",Format=cat(seq("l",i=1..cols)),RowSep=rowsep);
if Lisst=no then
out,key,p;
else
[out],key,p fi;
end:





##detrix

detrix := proc(lst)
  local mat,i,j,fmt,defaults,opts,help,leftsymbol,rightsymbol,pos;
defaults:=Help=no,Leftsymbol="|",Rightsymbol="|",Format="",Position=""; opts:=subs([op(select(type,[args],`=`)),defaults],[Help,Leftsymbol,Rightsymbol,Format,Position]);
 help:=opts[1]:
leftsymbol:=opts[2]: rightsymbol:=opts[3]: fmt:=opts[4]: pos:=opts[5]:
 if help=yes then mcprint("detrix(lst)  prints an array for use with latextools.  
Options:
Position=\"\"  places the array on the line of text.  \"t\"=top down, \"b\"=bottom up
   default is to center the array on the line.
Format=\"ccccc\" is the formatting string: l is left, r is right, | is vertical line
      there are many more options (see a latex manual)
Leftsymbol=\"\|\"  replace with desired left bracketing symbol
Rightsymbol=\"\|\" replace with desired right bracketing symbol"); RETURN(NULL) fi;
  if member(pos,{"top","t","bot","b"})  then pos:=cat("[",convert(pos[1],string),"]") fi;
  if fmt="" then
  fmt := cat(seq("c",i=1..nops(lst[1])-1),"c") fi;
  mat := cat("\\left",leftsymbol,"\\begin{array}",pos,"{",fmt,"}\n");
  for i from 1 to nops(lst) do
  for j from 1 to nops(lst[i]) do
  if  type(lst[i][j],string) then
  mat:= cat(mat,"\\mbox{",lst[i][j],"}") else
  mat:= cat(mat,`latex/print`(lst[i][j])) fi;
  if j < nops(lst[i]) then mat:= cat(mat," & ") elif i < nops(lst) then mat:=cat(mat," \\\\\n") else mat:= cat(mat," \n") fi:
  od od;
mat := cat(mat,"\\end{array}\\right",rightsymbol,"\n");
 end:

ansbox := proc()
 local pl,pl2,txt,fil,ht,wd,defaults,opts,help;
 defaults:=Help=no,Placement="c",Fill="",Textplace="c",Text="",Height=.4,Width=1:
 opts:=subs([op(select(type,[args],`=`)),defaults],[Help,Placement,Fill,Textplace,Text,Height,Width]);
 help:=opts[1]:
 if nargs>0 and StringTools[Search]("Help",convert(args[1],string))<>0 then help:=yes fi:
 if help=yes then mcprint("ansbox()  prints an answerbox for an exam or quiz written using
latextools.  
Options:
Height=.4  the default height (in inches) of the box
Width=1 the default width
Placement=\"t\"  places the answer box on the line of text.  t=top, c=center, b=bottom
Fill=\"\" use \"\\hfill\" or \"\\hspace{x in}\" to position the box in the remaining part of the line.
TextPlace=\"c\"  places the text in the box t = top, c=center, b=bottom
Text=\"\"  the text going into the box"); RETURN(NULL) fi;
 pl:=opts[2]:
 fil:=opts[3]:
 pl2:=opts[4]:
 txt:=opts[5]:
ht:=opts[6]:
 wd:=opts[7]:  
 cat("\\ ",fil,"\\fbox{\\parbox[",pl,"][",convert(ht,string),"in][",pl2,"]{",convert(wd,string),"in}{",txt,"\\hfill}}")
end:

parbox:=proc()
local text,t,defaults,opts,help,pos,width,txtpl,height,border;
defaults:=Help=no,Placement="t",Width="3in",Textplacement="t",Height="",Border=no;
opts:=subs([op(select(type,[args],`=`)),defaults],[Help,Placement,Width,Textplacement,Height,Border]);
help:=opts[1];
pos:=opts[2]:
width:=opts[3]:
txtpl:=opts[4]:
height:=opts[5]:
border:=opts[6]:
if help=yes then mcprint("parbox(text) outputs text in a parbox for latex.
Option:
Placement=\"t\"  for top. Use \"b\" for bottom and \"c\" for center
Width=\"3.25in\"  change width as desired.
Height=\"\" (optional)
Textplacement=\"t\" Use \"b\" and \"c\" as with placement (only works when height is set)
Border=no  set to yes to get a border around the parbox."); RETURN(NULL) fi;
text:= NULL:
for t in args do
if type(t,list) then text:=text,op(t)
elif type(t,`=`) and member(lhs(t),{Help,Placement,Width,Textplacement,Height,Border}) then next
else text:=text,t
fi;
od:
if height="" then txtpl:="" fi:
if height<>"" then height:=cat("[",height,"]"); txtpl:= cat("[",txtpl,"]") fi:
if border=no then   
    [ "\\parbox[",pos,"]",height,txtpl,"{",width,"}{",text,"}"]
else
   
[ "\\fbox{\\parbox[",pos,"]",height,txtpl,"{",width,"}{",text,"}}"] fi end:

minipage:=proc()
local text,t,defaults,opts,help,pos,width;
defaults:=Help=no,Placement="t",Width="3in";
opts:=subs([op(select(type,[args],`=`)),defaults],[Help,Placement,Width]);
help:=opts[1];
pos:=opts[2]:
width:=opts[3]:

if help=yes then mcprint("minipage(text) outputs text in a parbox for latex.
Option:
Placement=\"t\"  for top. Use \"b\" for bottom and \"c\" for center
Width=\"3.25in\"  change width as desired."); RETURN(NULL) fi;
text:= NULL:
for t in args do
if type(t,list) then text:=text,op(t)
elif type(t,`=`) and member(lhs(t),{Help,Placement,Width}) then next
else text:=text,t
fi;
od:   
    [ "\\begin{minipage}[",pos,"]","{",width,"}\n",text,"\n\\end{minipage}"]   
end:

picps := proc(n,pic,name)
local defaults,opts,help,h,w,writ,latx,ph,pw,fmt;
defaults:=Help=no,Width=240,Height=180,Write=yes,Latex=yes,Pwidth=120,Pheight=90;
opts:=subs([op(select(type,[args],`=`)),defaults],[Help,Width,Height,Write,Latex,Pwidth,Pheight]);
help:=opts[1]:
w:=opts[2]:
h:=opts[3]:
writ:=opts[4]:
latx:=opts[5]:
if latx=yes then fmt:=".ps" elif (latx=no or latx=gif) then fmt:=".gif" else fmt:=".jpeg" fi:
pw := opts[6]:
ph := opts[7]:
if help=yes then
mcprint("picps(n,pic,name) saves a plotstucture pic to cat(name,convert(n,string),\".ps\") in the
current directory and writes an includegraphics into latex source.
Options:
Latex = yes Change to gif or jpeg to get an html format.
Height=180 units are points
Width=240  units are points
Pheight=90  ps height
Pwidth=120  ps width
Write=yes  Change to no to reuse a previously stored .ps (or gif or jpeg) file"); RETURN(NULL) fi;
  if latx=yes then
if writ=yes then if ph>0 then
addimg(savepic(pic,cat(name,convert(n,string),fmt),Image=ps,Height=ph,Width=pw,
Plotoptions="portrait,noborder,shrinkby=0"),
Options=cat("height=",convert(ph,string),"pt,width=",convert(pw,string),"pt"),Latex=yes)
else
addimg(savepic(pic,cat(name,convert(n,string),fmt),Image=ps,
Plotoptions="portrait,noborder,shrinkby=0"),
Options="",Latex=yes) fi
else
addimg(cat(name,convert(n,string),fmt),
Options=cat("height=",convert(ph,string),"pt,width=",convert(pw,string),"pt"),Latex=yes) fi:
else
if writ=yes then
addimg(savepic(pic,cat(name,convert(n,string),fmt ),Image=gif,Height=h,Width=w),
Options=cat("height=",convert(h,string),"pt,width=",convert(w,string),"pt"))
else
addimg(cat(name,convert(n,string),fmt),
Options=cat("height=",convert(h,string),"pt,width=",convert(w,string),"pt"))
fi fi;
end:

#graphic
graphic:=proc()
local bill,l;
l := [args];
if type(l[1],`=`) then mprint("graphic(args) outputs a texline
  a\\includegraphics[width=b in,height=c in]{d}
where a=\"\" if nops(l)<4, else a=\"\\hfill\" if l[4]=-1 else a=\"\\hspace{l[4]}\"
      b=\"320pt\" and c=\"200pt\" if nops(l)=3 else b=l[2] and c=l[3]
      d=l[1] is the name of the graphic file."); RETURN(NULL) fi;  
if not member(nops(l),{1,3,4}) then ERROR("need 1,3, or 4 arguments.") fi;
bill:=cat("{",l[1],"}");
if nops(l)>1 then
   if type(l[2],string) then
      bill:=cat("[width=",l[2],",height=",l[3],"]",bill);
      else bill:=cat("[width=",l[2],"in,height=",l[3],"in]",bill);
   fi;
else bill:=cat("[width=320pt,height=200]",bill);
fi;
if nops(l)=4 then
   if type(l[4],string) then bill:=cat(l[4],"\\includegraphics",bill)
        elif l[4]<0 then
        bill:=cat("\\hfill\\includegraphics",bill);
        else bill:=cat("\\hspace{",l[4],"in}\\includegraphics",bill);
   fi;
else bill:=cat("\\includegraphics",bill)
   fi;
 
 
bill;
end:


bigcolorlist:=[[aquamarine,  .829686 ," 0.498039  1. 0.831373  C"],
[black,0," 0 0 0  C"],
[blue, .11," 0 0 1 C"],
[coral, .593843," 1   0.498039  .313725  C"],
[cyan, .7," 0 1 1  C"],
[brown, .30549," 0.64705882  0.16470588  0.16470588  C"],
[gold, .55498," 1  0.843137  0  C"],
[green, .59," 0  1 0  C"],
[darkgreen,.293843," 0 .5  0 C"],
[grey, .752941," 0.745098  0.745098  0.745098  C"],
[khaki, .592431," 0.941176 0.901961 0.54902  C"],
[magenta, .41," 1 0 1 C"],
[maroon, .291451," 0.690196 0.188235 0.376471  C"],
[navy, .179922," 0  0  0.501961  C"],
[orange, .37451," 0.80000000  0.19607843  0.19607843  C"],
[pink, .82949," 1 0.752941  0.796078  C"],
[plum, .774196," 0.91764706  0.67843137  0.91764706  C"],
[red, .3," 1 0 0  C"],
[sienna, .42698," 0.627451 0.321569 0.176471  C"],
[tan, .646078," 0.85882353  0.57647059  0.43921569  C"],
[turquoise, .844706," 0.25098 0.878431 0.815686  C"],
[violet, .234157," 0.30980392  0.18431373  0.30980392  C"],
[wheat, .832784," 0.960784 0.870588 0.701961  C"],
[white, 1," 1 1 1  C"],
[yellow, .89," 1 1 0  C"],
[aquamarine,  .701882 ," 0.43921569  0.85882353  0.57647059  C"],
[black,0," 0 0 0  C"],
[blue, .11," 0 0 1 C"],
[coral, .593843," 1   0.49803922  0  C"],
[cyan, .7," 0 1 1  C"],
[brown, .30549," 0.64705882  0.16470588  0.16470588  C "],
[gold, .55498," 0.80000000  0.49803922  0.19607843  C "],
[green, .59," 0  1 0  C"],
[grey, .752941," 0.75294118  0.75294118  0.75294118  C "],
[khaki, .592431," 0.62352941  0.62352941  0.37254902  C "],
[magenta, .41," 1 0 1 C"],
[maroon, .291451," 0.55686275  0.13725490  0.41960784  C "],
[navy, .179922," 0.13725490  0.13725490  0.55686275  C "],
[orange, .37451," 0.80000000  0.19607843  0.19607843  C "],
[pink, .82949," 1 0.752941176  0.7960784314  C "],
[plum, .774196," 0.91764706  0.67843137  0.91764706  C "],
[red, .3," 1 0 0  C "],
[sienna, .42698," 0.55686275  0.41960784  0.13725490  C "],
[tan, .646078," 0.85882353  0.57647059  0.43921569  C "],
[turquoise, .844706," 0.67843137  0.91764706  0.91764706  C "],
[violet, .234157," 0.30980392  0.18431373  0.30980392  C "],
[wheat, .832784," 0.84705882  0.84705882  0.74901961  C "],
[white, 1," 1 1 1  C "],
[yellow, .89," 1 1 0  C "],
[aliceblue,.962667,  " .941176   .972549  1.  C "],
[antiquewhite,.92898,  " .980392   .921569  .843137  C "],
[aquamarine,.829686,  " .498039   1.  .831373  C "],
[aquamarine,.701882,  " .43921569 .85882353 .57647059  C "],
[azure,.981176,  " .941176   1.  1.  C "],
[beige,.946078,  " .960784   .960784  .862745  C "],
[bisque,.911647,  " 1.   .894118  .768627  C "],
[black,0," 0 0 0  C"],
[blanchedalmond,.932157,  " 1.   .921569  .803922  C "],
[blue, .11," 0 0 1 C"],
[blueviolet,.355843,  " .541176   .168627  .886275  C "],
[brown,.309412,  " .647059   .164706  .164706  C "],
[burlywood,.743961,  " .870588   .721569  .529412  C "],
[cadetblue,.545176,  " .372549   .619608  .627451  C "],
[chartreuse,.738235,  " .498039   1.  0.  C "],
[chocolate,.501333,  " .823529   .411765  .117647  C "],
[coral,.625608,  " 1.   .498039  .313725  C "],
[cornflowerblue,.564627,  " .392157   .584314  .929412  C "],
[cornsilk,.965961,  " 1.   .972549  .862745  C "],
[crimson,.329373,  " .862745   .784314e-1  .235294  C "],
[darkblue,.595294e-1,  " 0.   0.  .545098  C "],
[darkcyan,.378824,  " 0.   .545098  .545098  C "],
[darkgoldenrod,.528941,  " .721569   .52549  .431373e-1  C "],
[darkgray,.658824,  " .662745   .662745  .662745  C "],
[darkgreen,.231373,  " 0.   .392157  0.  C "],
[darkgrey,.658824,  " .662745   .662745  .662745  C "],
[darkkhaki,.688431,  " .741176   .717647  .419608  C "],
[darkmagenta,.221882,  " .545098   0.  .545098  C "],
[darkolivegreen,.366667,  " .333333   .419608  .184314  C "],
[darkorange,.623922,  " 1.   .54902  0.  C "],
[darkorchid,.381373,  " .6   .196078  .8  C "],
[darkred,.162353,  " .545098   0.  0.  C "],
[darksalmon,.669882,  " .913725   .588235  .478431  C "],
[darkseagreen,.663294,  " .560784   .737255  .560784  C "],
[darkslateblue,.285373,  " .282353   .239216  .545098  C "],
[darkslategray,.272157,  " .184314   .309804  .309804  C "],
[darkslategrey,.272157,  " .184314   .309804  .309804  C "],
[darkturquoise,.564471,  " 0.   .807843  .819608  C "],
[darkviolet,.263961,  " .580392   0.  .827451  C "],
[deeppink,.409686,  " 1.   .784314e-1  .576471  C "],
[deepskyblue,.551922,  " 0.   .74902  1.  C "],
[dimgray,.411765,  " .411765   .411765  .411765  C "],
[dimgrey,.411765,  " .411765   .411765  .411765  C "],
[dodgerblue,.477294,  " .117647   .564706  1.  C "],
[firebrick,.298824,  " .698039   .133333  .133333  C "],
[floralwhite,.979216,  " 1.   .980392  .941176  C "],
[forestgreen,.372353,  " .133333   .545098  .133333  C "],
[gainsboro,.858824,  " .862745   .862745  .862745  C "],
[ghostwhite,.972078,  " .972549   .972549  1.  C "],
[gold,.795137,  " 1.   .843137  0.  C "],
[goldenrod,.651608,  " .854902   .647059  .12549  C "],
[gray,.741176,  " .745098   .745098  .745098  C "],
[green,.59,  " 0.   1.  0.  C "],
[greenyellow,.812627,  " .678431   1.  .184314  C "],
[grey,.741176,  " .745098   .745098  .745098  C "],
[honeydew,.974275,  " .941176   1.  .941176  C "],
[hotpink,.620157,  " 1.   .411765  .705882  C "],
[indianred,.49098,  " .803922   .360784  .360784  C "],
[indigo,.144314,  " .294118   0.  .509804  C "],
[ivory,.993098,  " 1.   1.  .941176  C "],
[khaki,.873725,  " .941176   .901961  .54902  C "],
[lavender,.910157,  " .901961   .901961  .980392  C "],
[lavenderblush,.958235,  " 1.   .941176  .960784  C "],
[lawngreen,.726627,  " .486275   .988235  0.  C "],
[lemonchiffon,.964549,  " 1.   .980392  .803922  C "],
[lightblue,.801333,  " .678431   .847059  .901961  C "],
[lightcoral,.632549,  " .941176   .501961  .501961  C "],
[lightcyan,.962353,  " .878431   1.  1.  C "],
[lightgoldenrod,.846235,  " .933333   .866667  .509804  C "],
[lightgoldenrodyellow,.959216,  " .980392   .980392  .823529  C "],
[lightgray,.827451,  " .827451   .827451  .827451  C "],
[lightgreen,.779882,  " .564706   .933333  .564706  C "],
[lightgrey,.827451,  " .827451   .827451  .827451  C "],
[lightpink,.802039,  " 1.   .713725  .756863  C "],
[lightsalmon,.722392,  " 1.   .627451  .478431  C "],
[lightseagreen,.519333,  " .12549   .698039  .666667  C "],
[lightskyblue,.740549,  " .529412   .807843  .980392  C "],
[lightslateblue,.523255,  " .517647   .439216  1.  C "],
[lightslategray,.518353,  " .466667   .533333  .6  C "],
[lightslategrey,.518353,  " .466667   .533333  .6  C "],
[lightsteelblue,.752392,  " .690196   .768627  .870588  C "],
[lightyellow,.986196,  " 1.   1.  .878431  C "],
[limegreen,.553098,  " .196078   .803922  .196078  C "],
[linen,.945137,  " .980392   .941176  .901961  C "],
[maroon,.356039,  " .690196   .188235  .376471  C "],
[mediumaquamarine,.667647,  " .4   .803922  .666667  C "],
[mediumblue,.884314e-1,  " 0.   0.  .803922  C "],
[mediumorchid,.504196,  " .729412   .333333  .827451  C "],
[mediumpurple,.526549,  " .576471   .439216  .858824  C "],
[mediumseagreen,.531882,  " .235294   .701961  .443137  C "],
[mediumslateblue,.485255,  " .482353   .407843  .933333  C "],
[mediumspringgreen,.642549,  " 0.   .980392  .603922  C "],
[mediumturquoise,.656275,  " .282353   .819608  .8  C "],
[mediumvioletred,.336588,  " .780392   .823529e-1  .521569  C "],
[midnightblue,.132078,  " .980392e-1   .980392e-1  .439216  C "],
[mintcream,.984471,  " .960784   1.  .980392  C "],
[mistyrose,.924588,  " 1.   .894118  .882353  C "],
[moccasin,.905608,  " 1.   .894118  .709804  C "],
[navajowhite,.885529,  " 1.   .870588  .678431  C "],
[navy,.552157e-1,  " 0.   0.  .501961  C "],
[navyblue,.552157e-1,  " 0.   0.  .501961  C "],
[oldlace,.961412,  " .992157   .960784  .901961  C "],
[olivedrab,.469529,  " .419608   .556863  .137255  C "],
[orange,.681765,  " 1.   .647059  0.  C "],
[orangered,.457333,  " 1.   .270588  0.  C "],
[orchid,.607922,  " .854902   .439216  .839216  C "],
[palegoldenrod,.888941,  " .933333   .909804  .666667  C "],
[palegreen,.823529,  " .596078   .984314  .596078  C "],
[paleturquoise,.856471,  " .686275   .933333  .933333  C "],
[palevioletred,.580196,  " .858824   .439216  .576471  C "],
[papayawhip,.944431,  " 1.   .937255  .835294  C "],
[peachpuff,.883765,  " 1.   .854902  .72549  C "],
[peru,.576078,  " .803922   .521569  .247059  C "],
[pink,.829059,  " 1.   .752941  .796078  C "],
[plum,.725529,  " .866667   .627451  .866667  C "],
[powderblue,.821059,  " .690196   .878431  .901961  C "],
[purple,.363059,  " .627451   .12549  .941176  C "],
[red, .3," 1 0 0  C"],
[rosybrown,.61098,  " .737255   .560784  .560784  C "],
[royalblue,.416471,  " .254902   .411765  .882353  C "],
[saddlebrown,.327451,  " .545098   .270588  .745098e-1  C "],
[salmon,.638275,  " .980392   .501961  .447059  C "],
[sandybrown,.705608,  " .956863   .643137  .376471  C "],
[seagreen,.409333,  " .180392   .545098  .341176  C "],
[seashell,.966784,  " 1.   .960784  .933333  C "],
[sienna,.397373,  " .627451   .321569  .176471  C "],
[skyblue,.73451,  " .529412   .807843  .921569  C "],
[slateblue,.417882,  " .415686   .352941  .803922  C "],
[slategrey,.490039,  " .439216   .501961  .564706  C "],
[snow,.983529,  " 1.   .980392  .980392  C "],
[springgreen,.644353,  " 0.   1.  .498039  C "],
[steelblue,.460353,  " .27451   .509804  .705882  C "],
[tan,.720431,  " .823529   .705882  .54902  C "],
[thistle,.789216,  " .847059   .74902  .847059  C "],
[tomato,.556941,  " 1.   .388235  .278431  C "],
[turquoise,.679373,  " .25098   .878431  .815686  C "],
[violet,.681843,  " .933333   .509804  .933333  C "],
[violetred,.377373,  " .815686   .12549  .564706  C "],
[wheat,.875608,  " .960784   .870588  .701961  C "],
[whitesmoke,.956863,  " .960784   .960784  .960784  C "],
[yellowgreen,.676627,  " .603922   .803922  .196078  C "],
[white, 1," 1 1 1  C"],
[yellow, .89," 1 1 0  C"]]:

cc:=[[aquamarine,  .701882 ," 0.43921569  0.85882353  0.57647059  C"],
[black,0," 0 0 0  C"],
[blue, .11," 0 0 1 C"],
[coral, .593843," 1   0.49803922  0  C"],
[cyan, .7," 0 1 1  C"],
[brown, .30549," 0.64705882  0.16470588  0.16470588  C "],
[gold, .55498," 0.80000000  0.49803922  0.19607843  C "],
[green, .59," 0  1 0  C"],
[grey, .752941," 0.75294118  0.75294118  0.75294118  C "],
[khaki, .592431," 0.62352941  0.62352941  0.37254902  C "],
[magenta, .41," 1 0 1 C"],
[maroon, .291451," 0.55686275  0.13725490  0.41960784  C "],
[navy, .179922," 0.13725490  0.13725490  0.55686275  C "],
[orange, .37451," 0.80000000  0.19607843  0.19607843  C "],
[pink, .82949," 1 0.752941176  0.7960784314  C "],
[plum, .774196," 0.91764706  0.67843137  0.91764706  C "],
[red, .3," 1 0 0  C "],
[sienna, .42698," 0.55686275  0.41960784  0.13725490  C "],
[tan, .646078," 0.85882353  0.57647059  0.43921569  C "],
[turquoise, .844706," 0.67843137  0.91764706  0.91764706  C "],
[violet, .234157," 0.30980392  0.18431373  0.30980392  C "],
[wheat, .832784," 0.84705882  0.84705882  0.74901961  C "],
[white, 1," 1 1 1  C "],
[yellow, .89," 1 1 0  C "]]:

correctcc:=[[aquamarine,  .829686 ," 0.498039  1. 0.831373  C"],
[black,0," 0 0 0  C"],
[blue, .11," 0 0 1 C"],
[coral, .593843," 1   0.498039  .313725  C"],
[cyan, .7," 0 1 1  C"],
[brown, .30549," 0.64705882  0.16470588  0.16470588  C"],
[gold, .55498," 1  0.843137  0  C"],
[green, .59," 0  1 0  C"],
[grey, .752941," 0.745098  0.745098  0.745098  C"],
[khaki, .592431," 0.941176 0.901961 0.54902  C"],
[magenta, .41," 1 0 1 C"],
[maroon, .291451," 0.690196 0.188235 0.376471  C"],
[navy, .179922," 0  0  0.501961  C"],
[orange, .37451," 0.80000000  0.19607843  0.19607843  C"],
[pink, .82949," 1 0.752941  0.796078  C"],
[plum, .774196," 0.803922 0.521569 0.247059  C"],
[red, .3," 1 0 0  C"],
[sienna, .42698," 0.627451 0.321569 0.176471  C"],
[tan, .646078," 0.85882353  0.57647059  0.43921569  C"],
[turquoise, .844706," 0.25098 0.878431 0.815686  C"],
[violet, .234157," 0.30980392  0.18431373  0.30980392  C"],
[wheat, .832784," 0.960784 0.870588 0.701961  C"],
[white, 1," 1 1 1  C"],
[yellow, .89," 1 1 0  C"]]:

#default styles

ABBREVSAMS :=
[["\\_thm","\\begin{thm}"],["\\_mht","\\end{thm}"],
["\\_lem","\\begin{lem}"],["\\_mel","\\end{lem}"],
["\\_mf","\\mathfrak "],["\\_mc","\\mathcal "],
["\\_prf","\\begin{proof}"],["\\_frp","\\end{proof}"],
["\\TEXTsymbol{\\backslash}","\\"],["\\$","$"],
["\\_\\{","_{"],["\\TEXTsymbol{<}","<"],["\\TEXTsymbol{>}",">"],
["\\}","}"],["\\{","{"],
["\_wlt","\\prec\\!\\prec"],["\\frac ","\\Frac "],
["\\symbol{94}","^"],["\\lim","\\Lim"],["\\lim_","\\Lim_"],
["\\symbol{126}","~"],["\\int _","\\Int _"],["\\int","\\Int"],
["\\emptyline"," "],["text{","\\mbox{"]]:
ABBREVS:= ABBREVSAMS:

AMSMACROS:=
"%\\swapnumbers
\\newtheorem{thm}{}[section]
\\newtheorem{lem}[thm]{Lemma}
\\newtheorem{cor}[thm]{Corollary}
\\theoremstyle{definition}
\\newtheorem{defn}{Definition}[section]
\\newtheorem{example}{Example}[section]
\\newtheorem{prob}{Problem}
\\theoremstyle{remark}
\\newtheorem*{rem}{Remark}
\\newtheorem*{note}{Note}":

DOCSTYLE:="[11pt]{article}":
DOCSTYLEAMS:="[11pt]{amsart}":

FONTS:="":

LENGTHS:="% tweak these to taste.
 \\AboveMapleSkip 5 pt%- space above an environment
 \\BelowMapleSkip 1 pt%- space below an environment
 \\AboveMaplePlot = 1\\AboveMapleSkip
 \\BelowMaplePlot= 1\\BelowMapleSkip
% \\MaplePlotHeight- vertical space reserved for a plot
% \\MaplePlotWidth- width reserved for a plot
% \\MaplePlotAngle- angle of rotatation
% \\LeftMapleSkip - the amount of left indentation
% \\MapleFont - The Maple font
\\def\\MapleFont{\\ttfamily}
% \\MapleSize - The size of the Maple font in mapleinput and
\\def\\MapleSize{\\scriptsize}
%                          maplettyout
% \\MapleLatexSize- The size of the Maple fonts in maplelatex
\\def\\MapleLatexSize{\\small}
% \\MapleFirstLine- controls ingoring first line feed
% \\MaplePrompttrue - controls insertion of prompt char
% \\MaplePromptString= {\\raise 1pt \\hbox{\$\\scriptstyle>\$\\space}}
 \\MaplePromptSecondary = {\\space\\space}
% \\MaplePromptSecondary- defines the secondary prompt string
% \\MapleSkip- amount of glue before and after
%displayed text
% \\MapleTab- number of spaces per tab (8)
\\def\\emptyline{\\vspace{6pt}}
\\setlength{\\oddsidemargin}{0in} \\setlength{\\evensidemargin}{0in}
\\textwidth 6.5in
\\topmargin  .5in
\\textheight 8.5in
% You may need to add your own paragraph styles.
\\DefineParaStyle{Bullet Item}
\\DefineParaStyle{Heading 1}
\\DefineParaStyle{Heading 2}
\\DefineParaStyle{Heading 3}
\\DefineParaStyle{Heading 4}
\\DefineParaStyle{Comment}
\\DefineParaStyle{Problem}
\\DefineParaStyle{Definition}
\\DefineParaStyle{List Item}
\\DefineParaStyle{Dash Item}
\\DefineParaStyle{Title}
\\DefineParaStyle{Author}
\\DefineParaStyle{Warning}
\\DefineParaStyle{Maple Plot}
\\DefineParaStyle{Error}
\\DefineParaStyle{Diagnostic}
\\DefineParaStyle{Maple Output}
\\DefineCharStyle{2D Comment}
\\DefineCharStyle{2D Math}
\\DefineCharStyle{Help Heading}
\\DefineCharStyle{Hyperlink}":

MACROS:= "\\newcommand{\\Int}{\\displaystyle\\int}
\\newcommand{\\Lim}{\\displaystyle\\lim}
\\newcommand{\\Frac}[2]{\\frac{\\textstyle #1}{\\textstyle #2}}":

PKGS := {maple2e,color,latexsym,graphicx}:
PKGSAMS := {maple2e,amsthm,amsfonts,color,latexsym,graphicx}:

PREAMBLE:= cat(LENGTHS,MACROS);
PREAMBLEAMS:= cat(LENGTHS,MACROS,AMSMACROS):

PSTYLE:= [["\\DefineParaStyle{prob}","\\DefineParaStyle{prob}"]]:
PSTYLEAMS := [["\\DefineParaStyle{prob}","%DefineParaStyle{prob}"],
["\\DefineParaStyle{lem}","%DefineParaStyle{lem}"],
["\\DefineParaStyle{thm}","%DefineParaStyle{thm}"]]:

SSFONTS:= "\\renewenvironment{Text Output}{\\small\\ttfamily\\mdseries}{}
 \\renewcommand{\\ttdefault}{courier}
 \\renewcommand{\\familydefault}{cmss}
 \\mathversion{bold}":

###local procedures
###colorfun
colorfun  := proc(clr,cc)
 local i,opts,rgb;
 opts:= subs(select(type,[args],`=`),[Unassign]);
  if  opts[1] <> yes then
   if not type(clr,integer) then
    for i from 1 to nops(cc) do
     if convert(clr,symbol)=cc[i][1] then
      rgb := remove(type, StringTools[Split](cc[i][3]," "),"");
      RETURN( cat(cc[i][1],`:= ()  -> COLOR(RGB,`,convert(rgb[1],symbol),`,`,
      convert(rgb[2],symbol),`,`,convert(rgb[3],symbol),`):`))
     fi;
    od;
   elif clr <= nops(cc) and clr > 0 then
    rgb := remove(type, StringTools[Split](cc[clr][3]," "),"");
    RETURN( cat(cc[clr][1],`:= ()  ->     
    COLOR(RGB,`,convert(rgb[1],symbol),`,`,convert(rgb[2],symbol),`,`,
    convert(rgb[3],symbol),`):`))
   fi;
   `not in list`;
  else for i from 1 to nops(cc) do if cc[i][1] <> tan then  
     unassign(cc[i][1])fi od;  
  fi;
end:
###end colorfun

###dupindex
dupindex := proc(files,path)
 local infiles,infile,outfile,line,lline,a,b,c,u,i,li;
 
 if not type(files,list) then
  infiles := [files]
 else
  infiles := files
 fi:
 currentdir(path);
 for infile in infiles do   
  infile := cat(infile,".tex");
  outfile := cat("tmp_",infile);
  try
   fopen(infile,READ,TEXT)
  catch "file already open":
   fclose(infile);
   fopen(infile,READ,TEXT);
  end try;

  line := readline(infile);

  if StringTools[Search]("NT) duped",line)>0 then  
   close(infile);
   next
  else
   line := StringTools[Substitute](line,"NT)","NT) duped")
  fi;

  while line<>0 do
   line:= StringTools[SubstituteAll](line,"QTR{word}","QTR{index}");
   line:= StringTools[SubstituteAll](line,"QTR{TXT CMD }","QTR{index}");
   line:= StringTools[SubstituteAll](line,"QTR{bookmark}","QTR{index}");
   a := [StringTools[SearchAll]("\\QTR{index}",line)]:
   if nops(a)>0 then
    if nops(a)>1 then
     u:=1;
     for i from 2 to nops(a) do
      li := StringTools[SubString](line,u..a[i]-1);
      if not StringTools[RegMatch]("QTR{index}{([^}]+)}",li,'b','c') then
       ERROR("something's fishy")
      else
       li := StringTools[Substitute](li,b,cat(b," \\textbf{",c,"} "))
      fi;
      writeline(outfile,li);
      u := a[i];
     od;
     line := StringTools[SubString](line,a[-1]..length(line));
    fi;
    u:=0;
    lline := line:
    line := readline(infile);
    while u < 6 and
      not StringTools[RegMatch]("QTR{index}{([^}]+)}",lline,'b','c') do
     lline := cat(lline,line);
     line := readline(infile):
     u:= u+1;
    od;
    lline := StringTools[Substitute](lline,b,cat(b," \\textbf{",c,"} "));
    writeline(outfile,lline);
    lline:=NULL:
    next;
   fi;
   writeline(outfile,line);
   line := readline(infile);
  od;

  close(infile);
  close(outfile);
  FileTools[Remove](infile);
  FileTools[Rename](outfile,infile);
  #system(cat("del ",infile));
  #system(cat("ren ",outfile," ", infile));
 od;
 if nops(files)<> 0 then
  mprint("index words duplicated")
 fi;
end:
###end dupindex

###escape
escape := proc(str)
 local st,e,i;
 if not type(str,string)  then
  RETURN(str)
 else
  e := [["\$","\\$"],["\#","\\#"],["\%","\\%"],
    ["\&","\\&"],["\~","\\~"],["\_","\\_"],
    ["\^","\\^"],["\{","\\{"],["\}","\\}"],
    ["dt\_",""],["td\_",""],["rt\_",""],
    ["lt\_table",""],["lt\_/table",""],["gt\_",""]];
  st := str;
  for i in e do
   st := StringTools[SubstituteAll](st,i[1],i[2])
  od;
 fi;
 st
end;
###end escape

###getstyles
getstyles := proc(rootname,files,path)
 local infiles,infile,outfile,line,stylelist,page;

 infile:= cat(rootname,".tex");
 stylelist := NULL;
 currentdir(path);

 try
  fopen(infile,READ,TEXT)
 catch "file already open":
  fclose(infile);
  fopen(infile,READ,TEXT);
 end try;

 line := readline(infile);

 while StringTools[Search]("begin{document}",line)=0 do
  stylelist:=stylelist,line;
  line := readline(infile);
 od;
 close(infile);
 
 if not type(files,list) then
  infiles := [files]
 else
  infiles := files
 fi:

 for infile in infiles do
  infile := cat(infile,".tex");
  try
   fopen(infile,READ,TEXT)
  catch "file already open":
   fclose(infile);
   fopen(infile,READ,TEXT);
  end try;
  line := readline(infile); page:=no;
  while line <> 0 and page = no do
  if StringTools[Search]("begin{document}",line)>0 then page:=yes; break fi;
  line := readline(infile);
  od;
  if page=no then close(infile); next
  else FileTools[Position](infile,1);
  line:= readline(infile);
  while StringTools[Search]("begin{document}",line)=0 do
   if (StringTools[Search]("DefinePara",line)>0 or
     StringTools[Search]("DefineChar",line)>0 ) and
     convert(StringTools[Search](StringTools[Drop](line,3),[stylelist]),`+`)=0
     then
      if StringTools[Take](line,3)="%*%" then
       stylelist:=stylelist, StringTools[Drop](line,3)
      else
       stylelist:= stylelist,line
      fi;
   fi;
   line:= readline(infile);
  od;
  close(infile);
 fi;
 od;
 stylelist;
end:
###end getstyles

###rootify
rootify := proc(files,path)
 local infiles,infile,outfile,line,defaults,opts,undo;
 defaults := Undo=no;
 opts := subs( [op(select(type,[args],`=`)),defaults],[Undo]);
 undo := opts[1]:
 
 if not type(files,list) then
  infiles := [files]
 else
  infiles := files
 fi:

 for infile in infiles do
  outfile:= cat(infile,"tmp.tex");
  infile := cat(infile,".tex");

  currentdir(path);
  try
   fopen(infile,READ,TEXT)
  catch "file already open":
   fclose(infile);
   fopen(infile,READ,TEXT);
  end try;

  line := readline(infile);
  if undo = no then
   if StringTools[Search]("%*%",line)>0 then
    close(infile);
    next
   fi;  
  else
   if StringTools[Search]("%*%",line)=0 then
    close(infile);
    next
   fi;
  fi;
 
  try
   fopen(outfile,WRITE,TEXT)
  catch "file already open":
   fclose(outfile);
   fopen(outfile,WRITE,TEXT);
  end try;

  while StringTools[Search]("\\begin{document}",line)=0 do
   if undo = no then
    writeline(outfile,cat("%*%",line));
   else
    writeline(outfile,StringTools[Substitute](line,"%*%",""))
   fi;
   line := readline(infile);
  od;

  if undo = no then
   writeline(outfile,cat("%*%",line));
  else
   writeline(outfile,StringTools[Substitute](line,"%*%",""))
  fi;
  line := readline(infile);

  if undo = no and StringTools[Search]("\\pagestyle{",line)>0 then
   writeline(outfile,cat("%*%",line))
  elif undo = yes and StringTools[Search]("\\pagestyle{",line)>0 then
   writeline(outfile,StringTools[Substitute](line,"%*%",""))
  else
   writeline(outfile,line)
  fi;
  line := readline(infile);
  while StringTools[Search]("end{document}",line)=0 do
   writeline(outfile,line);
   line := readline(infile)
  od;

  if undo = no then
   writeline(outfile,cat("%*%",line));
  else
   writeline(outfile,StringTools[Substitute](line,"%*%",""))
  fi;

  close(outfile);
  close(infile);
  FileTools[Remove](infile);
  FileTools[Rename](outfile,infile);
  #if system(cat("del ",infile))=0 then  
  #system(cat("ren ",outfile," ",infile)) else ERROR("can't delete ",infile) fi;
  if undo = no then
   mprint(cat(infile," rootified."));
  else
   mprint(cat(infile," derootified"))
  fi;
 od;
 mprint("finished rotorootering.");
end:
###end rootify

getitout:=proc(infil,pstyle,path)
 local infile,outfile,plist,i,line,skip,file,cur;
 if type(pstyle,list) then
 plist:=NULL:
 for i from 1 to nops(pstyle) do
 plist:=plist,convert(pstyle[i],string);
 od:
 else plist:=convert(pstyle,string):
 fi:
 plist:=[plist];  
 
infile := infil;  
 infile := cat(infile,".tex");
  currentdir(path);
 try
  fopen(infile,READ,TEXT)
 catch "file already open":
  fclose(infile);
  fopen(infile,READ,TEXT);
 end try;
  line := readline(infile);
 skip := 0;
 file :=NULL:
 cur:=NULL:
 while line <> 0 do
  if StringTools[Search]("\\begin{",line)>0 then
     if skip=0 then for i from 1 to nops(plist) do
       if StringTools[Search](cat("\\begin{",plist[i],"}"),line)>0 then
         skip:= plist[i]; fi; od: fi:
  fi;
  
  if skip<>0 and StringTools[Search](cat("\\end{",skip,"}"),line)>0 then
   skip:= 0;
  
  line:=readline(infile);next;
  fi;
  if skip=0 then file:=file,line  fi;
 line:=readline(infile);
 od:
file:=[file]:
fclose(infile);
try
  fopen(infile,WRITE,TEXT)
 catch "file already open":
  fclose(infile);
  fopen(infile,WRITE,TEXT);
 end try;
for i from 1 to nops(file) do
 writeline(infile,file[i])
 od:
fclose(infile):
end:

###end local procedures

###global procedures
###cover
cover := proc()
 local title,dte,posspts,defaults,i,help,pts,instructs,bottom,opts,middle;
 defaults := Help=no,
  Title="Test 2 Ma 310 002 Problem Solving for Teachers",
  Date="March 31, 2004",
  Posspts=[15,15,seq(13,i=1..5),15],
  Instructions="There are 8 problems on the test. Work each problem in the
   space provided. Use the back of the preceeding page if needed.
   You may use a calculator.  You may ask me to clarify the statement of a
   problem.  Please do not ask me to tell you if your answer is correct.
   Be as complete as you can in showing your reasoning. No credit will
   be given to an unsupported answer. Good problem solving!",
  Bottom="\\textbf{Name: }\\rule{3in}{.01in}";
 opts := subs([op(select(type,[args],`=`)),defaults],
  [Help,Title,Date,Posspts,Instructions,Bottom]);
 help := opts[1]:
 title := opts[2]:
 dte := opts[3]:
 pts := opts[4]:
 instructs := opts[5]:
 bottom := opts[6]:
 if help=yes then
  mprint("cover(); returns textoutput for exam cover
   options:
   Help=no
   Title=\"test\"
   Date=\"3/31/04\"
   Posspts=[15,15,20]  #if string then mcprints it as the middle of the cover page.
   Instructions=\"do well\"
   Bottom=\"\\textbf{Name:}\\rule{1in}{.01in}\"
  ");
  RETURN(NULL);
 fi;

 if type(pts,list) then
  middle :=
   "\\begin{center}
    \\Large \\textbf{Scoring}\\\\
    \\begin{tabular*}{4in}[t]{ccc}\\\\\n",
    seq(cat(convert(i,string)," & ",
     "\\rule{1in}{.01in}  & of ",convert(pts[i],string), "\\\\\n"),i=1..nops(pts)),
     "\\textbf{Total} & \\rule{1in}{.01in} &  of ",
     convert(add(pts[i],i=1..nops(pts)),string),
     " \\end{tabular*} \\end{center}\n":
 else
  middle := pts
 fi;

 cat("\\begin{titlepage}
   \\begin{center}
   \\LARGE\\textbf{ ",title,"}\\\\\n",dte,
   "\\end{center}
   \\noindent\\textbf{Instructions: }\\textit{",instructs,"}
   \\vspace{.7in}",
   middle,
   "\\vfill\n",
   bottom,
   "\\end{titlepage}");
end:
###end cover

##extractlatex
extractlatex := proc(infil,path)
 local infile,outfile,line,skip,pre,qnum,oline,out,
  finish,np,key,flag,help,opts,pr,i,flag2,np2,name,
  defaults,perm,prob,head,multiplicity,version,randomize,
  number,bill,ppp,probs,li,fixeps,prtkey;
 defaults := Probs=[seq(i,i=1..400)],
  Name="",
  Perm=[seq(i,i=1..400)],
  Head="",
  Multiplicity=1,
  Version="-1",
  Randomize=no,
  Number=400,
  PPP="",
  FixEps=yes,
  Key=no;
 opts := subs([op(select(type,[args],`=`)),defaults],
  [Help,Probs,Name,Perm,Head,Multiplicity,Version,
   Randomize,Number,PPP,FixEps,Key]);
 probs := opts[2]:
 name := opts[3]:
 perm := opts[4]:
 head := opts[5]:
 multiplicity := opts[6]:
 version := opts[7]:
 randomize := opts[8]:
 number := opts[9]:
 ppp := opts[10]:
 fixeps := opts[11]:
 prtkey := opts[12]:
 if name="" then
  name := infil
 fi;
 if head="" then
  head:=cat("\\section{Problems from ",escape(name),"}","\n")
 fi;

 if opts[1]=yes then
  mprint(cat("version ",VERSION)," extractlatex(\"worksheet\",\"path\") where
   worksheet is the name of a WHS worksheet
   you have exported to tex and path is the location of the directory which
   contains the export.
   It creates a file worksheet_la.tex in the same directory which contains
   all the extracted problems. Process this with latexit.
   First execute the worksheet (problem by problem) with  LATEX_ set to yes
   (for   latex only) and both (for both latex and html versions of the
   problems).
   Then export the worksheet to latex.  Then execute extractlatex.  
   Options:
    Probs=[seq(i,i=1..400)]   set to the list of problems to be extracted.
    Number=400   set to the maximum number of problems in a homework.
    Multiplicity=1   set to the multiplicity of the homework.
    Version=\"-1\"  set to any string to get a version.
    Randomize=no  set to yes to change the ordering of the extracted problems
     or to a specific permutation
    PPP=\"\"  set to 3 to get 3 evenly spaced problems on a page or to a list
     of the problem numbers you want newpages after or to a list of latex
     spacing strings.
    Head=\"\"  set to a homework Title string if wanted.
    Name=\"\"  set to the name you want for the extracted tex file.
    Key=no   set to yes if you want a key (and have provided one)");
  RETURN()
 fi;

 currentdir(path);
 bill := vers(version,multiplicity,number);
 if multiplicity>1 then
  opts[2]:= [seq(i*multiplicity,i=0..number-1)]+bill[1]
 fi;
 if randomize=yes then
  perm:=bill[2]  
 elif (type(randomize,list)) then
  perm:=randomize;
 else
  perm:=[seq(i,i=1..number)]
 fi:

 if fixeps=yes then
  fixalleps(infil,path,Color=yes)
 fi;

 prob := table([]);
 prob[0] := "":
 key := table([]);
 flag := 0;
 np := 0:
 pr:= opts[2];
 np2:=0;

 finish := proc()
  writeline(outfile,prob[0]);
  ###ppp
  for i from 1 to np2 do
   if  nops([prob[perm[i]]])>1  then
   writeline(outfile,cat(prob[perm[i]],"\\ \\\\\n")) else mprint("problem here");next  fi;
   if ppp<>"" then   
    if type(ppp,integer) then
     if irem(i,ppp)=0 then
      writeline(outfile,"\\newpage")
     else  
      writeline(outfile,"\\ \\vfill\n\\ ")
     fi
    elif (type(ppp,set) or type(ppp,list)) then
     if type(ppp[1],string) then
      writeline(outfile,ppp[i])  
     elif member(i,{op(ppp)}) then
      writeline(outfile,"\\newpage")  
     fi;
    fi;
   fi;
  od;
  writeline(outfile,"\\end{enumerate}");
  if prtkey=yes then
   writeline(outfile,"\\newpage");
   writeline(outfile,cat("\\section{Answer Key for ",escape(convert(name,string)),"}"));
   writeline(outfile,"\\begin{enumerate}");
   for i from 1 to np2 do
    writeline(outfile,cat(key[perm[i]]))
   od;
   writeline(outfile,"\\end{enumerate}");
  fi;
  writeline(outfile,line);
  fclose(infile);
  fclose(outfile);
  mprint(cat(name,"_la.tex created: ",np2," problems"));
 end;

 infile := infil;  
 infile := cat(infile,".tex");

 outfile:= cat(name,"_la.tex");
 currentdir(path);
 close(infile);
 close(outfile);
 try
  fopen(infile,READ,TEXT)
 catch "file already open":
  fclose(infile);
  fopen(infile,READ,TEXT);
 end try;
 try
  fopen(outfile,WRITE,TEXT)
 catch "file already open":
  fclose(outfile);
  fopen(outfile,WRITE,TEXT);
 end try;

 line := readline(infile);
 while line <> "\\begin{document}" do
  prob[0]:=prob[0],line;
  line := readline(infile);
 od;
 prob[0]:=prob[0],line,"\n";
 prob[0]:=prob[0],head;
 prob[0]:=prob[0],"\\begin{enumerate}","\n";
 line := readline(infile);

 while line <> 0 do
  if StringTools[Search]("\\end{document}",line)>0 then
   finish();
   RETURN();
  fi;

  if StringTools[Search]("{flushleft}",line)>0 or
    StringTools[Search]("\\emptyline",line)>0 then
   line:= ""
  fi;

  if StringTools[Search]("\\_OMIT",line)>0 or
    StringTools[Search]("_OMIT",line)>0 then
   while StringTools[Search]("\\_TIMO",line)=0 and
     StringTools[Search]("_TIMO",line)=0  and
     line<> 0 and line<>"\\end{document}" do
    line := readline(infile);
   od;
   if line="\\end{document}" then
    finish();
    RETURN()
   fi;
   line := readline(infile);
   next;
  fi;

  if line = "_KEY" and flag2=1 then
   key[np2] := "\\item \n";
   line := readline(infile);
   while line <> "_YEK" and line <> 0 do
    if StringTools[Search]("\\begin{maplettyout}",line)>0 then
     line := "";
     li := readline(infile);
     if li = "_YEK" then
      line := li;
      flag2 := 0;
      break;
     fi;
     while StringTools[Search]("maplettyout",li)=0 do
      line := cat(line," ",li);
      li := readline(infile);
     od;
    fi;

    if StringTools[Search]("{flushleft}",line)>0 or
      StringTools[Search]("\\emptyline",line)>0 or
      StringTools[Search]("maplettyout",line)>0 then  
     line:=""   
    else
     key[np2] := key[np2],line ,"\n"
    fi;
    line := readline(infile);
   od;
   if line = "_YEK" then
    line := "":
    flag2:=0
   fi;
  fi;

  if line = "_LATEX" and np2 < number then
   np := np+1;
   if np = pr[1] then
    if nops(pr)=1 then
     pr:=[0]
    else
     pr:=[seq(pr[i],i=2..nops(pr))]
    fi;
    flag:=1;
    flag2:=1;
    np2:=np2+1;
    prob[np2]:="":

    line := readline(infile);
    while line <> "_XETAL" and line <> 0 do
     if flag2 = 1 and StringTools[Search]("\\begin{maplettyout}",line)>0 then
      line := "";
      li := readline(infile);
      if li = "_XETAL" then  
       break
      fi;
      while StringTools[Search]("maplettyout",li)=0 do
       line := cat(line," ",li);
       li := readline(infile);
      od;
     fi;

     if StringTools[Search]("{flushleft}",line)>0 or
        StringTools[Search]("\\emptyline",line)>0 or
        StringTools[Search]("maplettyout",line)>0 or
        line="" then
      NULL  
     else
      prob[np2]:=prob[np2],line,"\n";
     fi;
     line := readline(infile);
    od;
    flag:=0;
   fi;
  fi;

  line := readline(infile);
 od;
 finish();

end:
###end extractlatex

###fixeps
fixeps  := proc(infil)
 local defaults,outfile,bill,gotit,line,cv,gs,gst,rt,lt,opts,cc,coler,help;
 defaults:= Color=yes,Colorlist=bigcolorlist,Help=no;
 opts:= subs( [op(select(type,[args],`=`)),defaults],[Color,Colorlist,Help]);
 coler:=convert(opts[1],string):
 cc := opts[2]:
 help := opts[3]:
 if help=yes then
  mprint("fixeps(infile) will remove the border from the Maple eps infile.
  options:  
  Color=no.  Set to yes to colorize infile according to the grayscale to RGB
   table in bigcolorlist.
  Colorlist=bigcolorlist.  Set to another file if you have one.");  
  RETURN(NULL)
 fi;

 cv := proc(gs)
  local  i,m,mi,j;
  m := 1; j = 1;  
  for i from 1 to nops(cc) do
   mi :=abs(op(sscanf(gs,"%g")) - cc[i][2]);
   if mi<.0001 then
    RETURN(cc[i][3])
   fi;
   if mi < m then
    m := mi;
    j := i
   fi;
  od;
  cc[j][3];
 end;

 outfile := cat("tmp_",infil);
 try
  fopen(infil,READ,TEXT)
 catch "file already open":
  fclose(infil);
  fopen(infil,READ,TEXT);
 end try;
 try
  fopen(outfile,WRITE,TEXT)
 catch "file already open":
  fclose(outfile);
  fopen(outfile,WRITE,TEXT);
 end try;
 gotit := 0;
 line := readline(infil);
 writeline(outfile,line);
 line := readline(infil);

 if StringTools[Search]("Maple plot recolorized by latextools",line)=0 then
  line :=StringTools[Substitute](line,"Maple plot",
   "Maple plot recolorized by latextools")
 else
  fclose(outfile);
  fclose(infil);
  FileTools[Remove](outfile);
  RETURN(1)
 fi;
 while line <> 0  do

 line := StringTools[SubstituteAll](line,
   "drawborder true","drawborder false");

 if coler="yes"  then
  if StringTools[Search](" G", line) > 0  then
   if StringTools[Search]("setdash" ,line) > 0 then   
    lt:= StringTools[FirstFromRight]("h",line);
    rt:= StringTools[FirstFromRight]("G",line);
    gs := StringTools[SubString](line,lt+1..rt);
    gst := StringTools[SubString](line,lt+1..rt-1);
    line := StringTools[SubstituteAll](line,gs,cv(gst));
   elif length(line) < 14  then
    rt := StringTools[FirstFromLeft]("G",line);
    gs := StringTools[SubString](line,1..rt);
    gst := StringTools[SubString](line,1..rt-1);
    line := StringTools[SubstituteAll](line,gs,cv(gst));
   fi;
  fi;
 fi;
 writeline(outfile,line);
 line := readline(infil);
od;

fclose(infil);  
fclose(outfile);
bill := FileTools[Remove](infil);
#bill := system(cat("del ",infil));
#if bill = 0 then
 #bill := system(cat("ren ",outfile," ",infil));
#else ERROR("cannot delete ",infil) fi;
 #if bill <> 0 then ERROR("cannot rename ",outfile)
#fi;
FileTools[Rename](outfile,infil)
end:
###end fixeps

###fixalleps
fixalleps := proc(nm,path)
 local ld,f,i,n;
 f := proc(nm,path)
  local st,ld,out,g,n;
  n:= length(nm);
  g := proc(s)
   if length(s)>=4 and substring(s,-4..-1)=".eps" then
    true
   else
    false
   fi
  end;
  ld := select(g,FileTools[ListDirectory](path));
  g := proc(s)
   if length(s)>=n and substring(s,1...n)=nm then
    true
   else
    false
   fi
  end;
  select(g,ld);
 end:  
 
 ld := f(nm,path);
 n:=0:
 for i in ld do
  if fixeps(i,Color=yes)=1 then
   n := n+1
  fi;
 od;
 if n= nops(ld) then
  mprint(" The ",nm," eps files are already recolorized.")
 elif n > 0 and n < nops(ld) then
  mprint(convert(n,string)," of the ",nm," eps files were recolorized.")
 else
  mprint(" The ",nm," eps files were recolorized.")
 fi;
 NULL;
end;
###end fixalleps

###getnums
getnums := proc(file,path,vers)
 local junk,perm,j,oc,a,b,c,d,e,defaults,opts,line,help,i,f,kde,offset;
 oc := table([seq(convert(i,string)=i,i=1..1000)]);
 defaults:=Help=no,KDEInterface=no,Offset=0;
 opts := subs([ op(select(type,[args],`=`)),defaults],
   [Help,KDEInterface,Offset]);
 help := opts[1]:kde:=opts[2]:offset:=opts[3]:
 if help=yes then
  mprint(
   "To get the sequence of absolute problem numbers in a WHS or KDE homework,
   Retrieve the homework and View the source.
   Save the source as a txt file (say junk.txt in a temporary spot, say c:/temp)
   getnums(\"junk.txt\",\"c:/temp\",vers) returns a list of 4 things:
   the version number, the list of relative problems sorted to the order
   that the absolute problem numbers are presented in the homework, and
   the sorted list of absolute problem numbers.
   Options:  
   Help = no
   KDEInterface=no  set to yes for appalmsp interface.
   Offset=0 set to 1 if makeheader is used, i if i survey questions at the top.");
  RETURN(NULL)
 fi;
 currentdir(path);

 try
  fopen(file,READ,TEXT)
 catch "file already open":
  fclose(file);
  fopen(file,READ,TEXT);
 end try;
 line := readline(file);
 junk := NULL:
 perm := NULL;
 if kde=no then j:=" />" else j:="></a>" fi;
 while line<>0 do
  if StringTools[RegMatch]
    (cat("name=\"([0-9]+)\"",j,"Question ([0-9]+)<"),line,'c','b','a')  
  then
   junk := junk,[parse(a),parse(b)];
  fi:
  line:= readline(file);
 od;
 fclose(file);
 junk := [junk];
 f := proc(a,b)
  if a[2]<b[2] then
   true
  else
   false
  fi
 end:
 junk := sort(junk,f);
 perm := NULL:
 [[vers],[seq(junk[i][1],i=1..nops(junk))], [seq(junk[i][2]-offset,i=1..nops(junk))],file];
end:
###end getnums

###latextoolshelp
latextoolshelp := proc()
 mprint(cat("latextools version ",VERSION,": A package to process maple export to latex.
  In all uses, you must export your worksheets to latex to get output.
  To prepare an exam, use makexam.  See makexam(Help=yes); for help.
     Note: There are examples posted at the MCtools Page (msc.uky.edu/carl)
  To process a single worksheet, you can use latexit. See latexit(Help=yes) for help.
  To combine several worksheets with a rootfile, use rootwork.  See rootwork(Help=yes)   for help.
  To process a WHS homework prepared with MCtools[tagit] (Nov 10 2003 or later), regenerate the
  tagit homework with  LATEX_:=yes, then export to latex, then process it with latexit   using the
  option WHSprobs=yes.

 The package also contains words to process the html export from Maple.
 Export to html, then use
 htmlit(\"worksheet\",\"path\") to process. See htmlit(Help=yes) for help.
 To create an html root, use
 htmlrootwork(\"rootname\",\"path\",Files=[\"file1\",\"file2\",...]); See  htmlrootwork(Help=yes) for help.

 The package also contains three words, mwsit, unmwsit and mwsrootwork, which
 manage the bookmarks of a group of one or more worksheets.
 See mwsit(Help=yes) and mwsrootwork(Help=yes) for help."));
end;
###end latextoolshelp

###mprint
mprint := proc()
 local fmt,fmtnl,ARGS,c;
 c := proc(g)
  convert(g,string)
 end:
 ARGS := map(c,[args]):
  if nops(ARGS)=0 then
   ARGS:=[""]
  fi;
  fmt := "%s";
 fmtnl:="%s\n":    printf(cat(seq(fmt,i=1..nops(ARGS)-1),fmtnl),seq(ARGS[j],j=1..nops(ARGS)));
end:
###end mprint

###showgs
showgs  := proc(clr,r,g,b)
 local pl1,tit,pout,getgs,opts;
 opts := subs( select(type,[args],`=`),[DataOnly,Help]);
 if opts[2]=yes then
  mprint("showgs(clr,r,g,b); returns the greyscale number obtained  from the r g b   
  values.  \nThe color name clr is put in a list with the greyscale number.");
  RETURN(NULL);
 fi;
  
 getgs := proc(clr,infil)
  local line,lt,rt,gs;
  try
   fopen(infil,READ,TEXT)
  catch "file already open":
   fclose(infil);
   fopen(infil,READ,TEXT);
  end try;
  line := readline(infil);
  while line <> 0 do
   if StringTools[Search](" G", line) > 0 and
      StringTools[Search]("setdash" ,line) > 0 then
    lt := StringTools[FirstFromRight]("h",line);
    rt := StringTools[FirstFromRight]("G",line);
    gs := StringTools[SubString](line,lt+1..rt-1);
    close(infil);
    RETURN([convert(clr,symbol),parse(gs)])
   fi;
   line:= readline(infil);
  od;
  close(infil);
  1;
 end:

 pout := cat(convert(clr,string),".eps"):
 pl1 := plots[display](plottools[polygon]([[0,0],[1,0],[1/2,1]],
   color=COLOR(RGB,r,g,b)),axes=none);
 plotsetup(ps,plotoutput=pout);
 print(pl1);
 plotsetup(default);
 tit := getgs(clr,pout);
 if tit <> 1 and convert(opts[1],string)="DataOnly" then
  print(evaln(colorname)=tit[1],evaln(rgbcode)=[r,g,b],
    evaln(grayscale)=tit[2]);
  print(pl1);
  RETURN(NULL);
 elif tit <> 1 then
  RETURN(cat(`[`,tit[1],`,`,convert(tit[2],symbol),`, "`,
   convert(r,symbol),`  `,convert(g,symbol),`  `,convert(b,symbol),`"]`))  
 else
  ERROR("Problem with getgs")
 fi;
end:
###end showgs

###begin getitout
getitout:=proc(infil,pstyle,path)
 local infile,outfile,plist,i,line,skip,file,cur;
 if type(pstyle,list) then
 plist:=NULL:
 for i from 1 to nops(pstyle) do
 plist:=plist,convert(pstyle[i],string);
 od:
 else plist:=convert(pstyle,string):
 fi:
 plist:=[plist];  
 
infile := infil;  
 infile := cat(infile,".tex");
  currentdir(path);
 try
  fopen(infile,READ,TEXT)
 catch "file already open":
  fclose(infile);
  fopen(infile,READ,TEXT);
 end try;
  line := readline(infile);
 skip := 0;
 file :=NULL:
 cur:=NULL:
 while line <> 0 do
  if StringTools[Search]("\\begin{",line)>0 then
     if skip=0 then for i from 1 to nops(plist) do
       if StringTools[Search](cat("\\begin{",plist[i],"}"),line)>0 then
         skip:= plist[i]; fi; od: fi:
  fi;
  
  if skip<>0 and StringTools[Search](cat("\\end{",skip,"}"),line)>0 then
   skip:= 0;
  
  line:=readline(infile);next;
  fi;
  if skip=0 then file:=file,line  fi;
 line:=readline(infile);
 od:
file:=[file]:
fclose(infile);
try
  fopen(infile,WRITE,TEXT)
 catch "file already open":
  fclose(infile);
  fopen(infile,WRITE,TEXT);
 end try;
for i from 1 to nops(file) do
 writeline(infile,file[i])
 od:
fclose(infile):
end:
###end getitout


###latexit
latexit  := proc(infil,path)
 local infile,outfile,line,skip,abbrev,pre,bill,opts,i,pars,ld,f,j,k,
       minput,pline,ckclr,getdate,texit,oline,s,lline,defaults,docstyle,
       preamble,extrapreamble,pkgs,extrapkgs,abbrevs,extraabbrevs,styles,extrastyles,
       purpose,cc,dvips,yap,numpass,fxeps,coler,help,whsprobs,picwidth,noempties,
       ttyout,fontsize,flag1,flag2,genabbrevs,hellobill,neww,lfile,hspc,supress;
 defaults := NumPass=1,FixEps=yes,Color=yes,Docstyle=DOCSTYLE,
       Pkgs=PKGS,Preamble=PREAMBLE,Abbrevs=ABBREVS,Styles=PSTYLE,CC=bigcolorlist,
       Dvips=yes,Yap=no,Help=no,WHSprobs=no,Picwidth=2.5,Purpose="",
       ExtraPkgs={},ExtraPreamble="",ExtraAbbrevs=[],ExtraStyles="",
       FontSize="",GenAbbrevs=[["\\frac ","\\Frac "],["\\lim _","\\Lim _"],
       ["\\int _","\\Int _"]],New=yes,Supress="":
 opts := subs([ op(select(type,[args],`=`)),defaults],
      [NumPass,FixEps,Color,Docstyle,Pkgs,Preamble,Abbrevs,Styles,CC,Dvips,Yap,
      Help,WHSprobs,Picwidth,Purpose,ExtraPkgs,ExtraPreamble,ExtraAbbrevs,
      ExtraStyles,FontSize,GenAbbrevs,New,Supress]);#print(opts);
 help := opts[12]:
  if help = yes then
  mprint(cat(convert(VERSION,string),"\nExport your worksheet to latex.
  Then\n latexit(\"worksheet\",\"path\") where
  worksheet is the name of the worksheet (omit the .tex suffix)
  path is the path to the directory with the exported tex files, eg, c://temp
  Options:
  New=yes   set to no to latex again after hand changes.
  NumPass=2 is the number of passes through latex
  FixEps=yes: set to no to keep the pictures grayscale
  Color:  set to no to keep the fontcolor black
  Docstyle=DOCSTYLE,
  Pkgs=PKGS,ExtraPkgs=\"\",
  Preamble=PREAMBLE,ExtraPreamble=\"\",
  Abbrevs=ABBREVS,ExtraAbbrevs=[],
  Styles=PSTYLE,ExtraStyles=\"\"  
  Dvips=no: set to no if you want to generate postscript by hand
  Help=no: set to yes to get this message
  WHSprobs=no: set to yes if you want to process a WHS homework which has latex   
  versions of
  the problems (use MCtools Nov 15 2003 or higher with LATEX_ set to yes or both before           you
  re-tagit and export to latex)
  Picwidth=2.5: set to larger or smaller width in inches to change the default size of       diagram
  (Note: Import external eps, png, bmp, jpg files with
  _pic[name.xxx;bb=llx lly urx ury,height=yin,width=xin] in Latex Char style)
  Purpose=\"notes\":  set to amspaper to use ams styles.
  Supress=\"\"  set to mapleinput to remove the mapleinput before latexing, or [mapleinput,maplettyout]
     to remove also the maplettyout.  Get other styles by inspecting the latex source file." ));
  RETURN(NULL)
 fi;
 hspc:="";
 numpass := opts[1]:
 fxeps := opts[2]:
 coler := convert(opts[3],string):
 docstyle := opts[4]:
 pkgs := opts[5]:
 preamble := opts[6]:
  abbrevs := opts[7]:
 styles := opts[8]:
 cc := opts[9]:
 dvips := opts[10]:
 yap := opts[11]:
 
 whsprobs := opts[13]:
 picwidth := opts[14]:
 purpose := opts[15]:
 extrapkgs := opts[16]:
 flag2 := 0;
 extrapreamble := opts[17]:
 extraabbrevs := opts[18]:
 extrastyles := opts[19]:
 fontsize := opts[20]:
 genabbrevs := opts[21]:
 neww:=opts[22]:
supress:=opts[23]:
 currentdir(path);
  #if neww=yes then
 preamble := cat(preamble,extrapreamble,"\n\\begin{document}");
 if nops(extraabrevs)>0 then  
  abbrevs := [op(abbrevs),op(extraabbrevs)];
 fi;

 if purpose=amspaper then
  docstyle := DOCSTYLEAMS;
  preamble := cat(PREAMBLEAMS,extrapreamble,"\n\\begin{document}");
  pkgs := PKGSAMS:
  styles := PSTYLEAMS;
 fi;

 if fontsize<>"" then
  docstyle := StringTools[Substitute](docstyle,"11pt",fontsize)
 fi;

 pkgs := convert( pkgs union extrapkgs,string);
 if extrastyles<>"" and op({op(map(nops,extrastyles))})=2 then
  styles := [op({op(styles)} union {op(extrastyles)})]
 fi;

 #imherenow
 f := proc(nm,path)
  local st,ld,out,g,n;
  n := length(nm);
  g := proc(s)
   if length(s)>= 4 and substring(s,-4..-1)=".eps" then
    true
   else
    false
   fi
  end;

  ld := select(g,FileTools[ListDirectory](path));
  g := proc(s)
   if substring(s,1...n)=nm then
    true
   else
    false
   fi
  end;
  select(g,ld);
 end:  
 ###end f

 ###ckclr
 ckclr := proc(line)
  local l;
  l:=line:
  if StringTools[Search]("\\color",line)=0 then
  l := StringTools[SubstituteAll](l,"\\begin{maplettyout}",
   "\\color[rgb]{.1,0,.7}\\begin{maplettyout}");
  l := StringTools[SubstituteAll](l,"\\begin{mapleinput}",
   "\\begin{mapleinput}\\color{red}");
  l := StringTools[SubstituteAll](l,"\\begin{maplegroup}",
   "\\begin{maplegroup}\\color{black}");
  l := StringTools[SubstituteAll](l,"\\begin{maplelatex}",
   "\\begin{maplelatex}\\color{blue}");
  l := StringTools[SubstituteAll](l,"\\end{maplelatex}",
   "\\end{maplelatex}\\color{black}");
  l := StringTools[SubstituteAll](l,"\\begin{Text Output}",
   "\\begin{Text Output}\\color{blue}");
  l := StringTools[SubstituteAll](l,"\\end{Text Output}",
   "\\end{Text Output}\\color{black}") fi;
  
  l;
 end;
 ###end ckclr

 ###getdate
 getdate :=proc()
  StringTools[FormatTime](%c);
 end:
 ###end getdate

 if neww=yes then

###put remove mapleinput here.
 if supress<>"" then #print(infil,supress,path);
 getitout(infil,supress,path);
 fi;


 if whsprobs=only then
  extractlatex(infil,path);
  fixalleps(infil,path);
  latexit(cat(infil,"_la"),path,FixEps=no);
  RETURN();
 elif whsprobs=texonly then
  extractlatex(infil,path);
  RETURN()
 elif whsprobs = yes then
  extractlatex(infil,path);
  fixalleps(infil,path);
  latexit(cat(infil,"_la"),path,FixEps=no)
 fi;

 dupindex(infil,path);

 infile := infil;  
 infile := cat(infile,".tex");

 outfile := cat(infil,"whs.tex");
 currentdir(path);
 try
  fopen(infile,READ,TEXT)
 catch "file already open":
  fclose(infile);
  fopen(infile,READ,TEXT);
 end try;
 try
  fopen(outfile,WRITE,TEXT)
 catch "file already open":
  fclose(outfile);
  fopen(outfile,WRITE,TEXT);
 end try;

 writeline(outfile,cat("%%%%Latex modified by WHS ",getdate()));
 line := readline(infile);
 skip := 0;
 pre := 0;
 minput := 0;
 ttyout := 0;
 texit := 0;
 noempties :=0;

 while line <> 0 do
  
  
   if pre=1 and coler="yes" then line:=ckclr(line) fi:
   if line="\\mapleresult" then line:=readline(infile); next; fi;  #1/31
  if StringTools[Search]("\\begin{textoutput}",line)>0 then
   ttyout:= 1;
  fi;
  if StringTools[Search]("\\end{textoutput}",line)>0 then
   ttyout:= 0;
  fi;
  if StringTools[Search]("QM_[",line)>0 then
   noempties:= 1;
  fi;
  if StringTools[Search]("SKIP_",line)>0 then
   noempties:= 0;
  fi;
  if line = "\\emptyline" and noempties=1 then
   line := readline(infile);
   next
  fi:

  if StringTools[Search]("\\begin{flushleft}",line)>0 or
     StringTools[Search]("\\end{flushleft}",line)>0 then
   line := readline(infile);
   next
  fi;

  if StringTools[Search]("BEGINHINT_hint",line)>0 then
   line:= "\\textbf{Hint:}"
  fi;
  if StringTools[Search]("ENDHINT_hint",line)>0 then
   line:= readline(infile);
   next
  fi;

  if pre = 0 then
   if line ="\\documentclass{article}" then
    line:=cat("\\documentclass",docstyle)
   fi;
  if line ="\\usepackage{maple2e}" then
   line:=cat("\\usepackage",pkgs)
  fi;
  for s in styles do
   if not type(s,list) and nops(s)<> 2 then
    ERROR("ExtraStyles must be a list of pairs")
   else
    line := StringTools[Substitute](line,op(s))
   fi;
  od:

  if line="\\begin{document}" then
   readline(infile);
   line:= preamble
  fi;
 fi;

 if StringTools[Search]("\\_GROUP",line)>0 then
  line := "";  
  lline := readline(infile);
  while not StringTools[Search]("\\end{document",line) =0  and
        not StringTools[Search]("\_POURG",line)= 0 do
   if lline ="\_POURG" then
    lline:= ""
   fi;
   line := line,lline;
  od;
 fi;
 ###
 if line = "_KEY" or line="_LATEX" then
  flag2 := 1;
  writeline(outfile,"\\end{maplettyout}");
  if line="_LATEX" then
   flag1 := FileTools[Position](infile);       
   readline(infile);
   readline(infile);
   readline(infile);
   line := readline(infile);
   if StringTools[Search]("\\item",line)>0 then
    line := "";
   else
    FileTools[Position](infile,flag1);
    line:= "" fi
   else  
    readline(infile);
    line := ""
   fi
  fi;
  if line = "_YEK" or line="_XETAL" then
   flag2 := 0;
   if coler="yes" then
     writeline(outfile,"\\color[rgb]{.545,0,0}\\begin{maplettyout}") else
     writeline(outfile,"\\begin{maplettyout}")
   fi;
   line := "";
  fi;
 
  if (flag2=1 or texit=1) and (StringTools[Search]("{flushleft}",line)>0
     or StringTools[Search]("\\emptyline",line)>0
     or StringTools[Search]("maplettyout",line)>0) then   
   line := "hellobill";
  fi;
  ###

  if StringTools[Search]("\\begin{mapleinput}",line)>0 then
   minput := 1  
  fi;
  if StringTools[Search]("\\end{mapleinput}",line)>0 then
   minput := 0;  
  fi;
  if StringTools[Search]("\\begin{document}",line)>0 and not
     StringTools[Search]("\"\\begin{document}",line)>0 then
   pre := 1;  
  fi;
  if StringTools[Search]("\\_LATEX",line)>0 then
   line:=StringTools[SubstituteAll](line,"\_LATEX"," ");
   if ttyout=1 then
    line := "\\end{textoutput}"
   fi;
   texit := 1;  
  fi;

  
  if StringTools[Search]("\_XETAL",line)>0 then
   line:=StringTools[SubstituteAll](line,"\_XETAL"," ");
   texit :=0;  
  fi;
 
  if StringTools[Search]("\\_OMIT",line)>0  then
   skip := 1
  fi;
  if StringTools[Search]("\\_TIMO",line)>0 and         
     StringTools[Search]("StringTools[Search]",line)= 0 then
   skip := 0;
   line:= ""
  fi;
  if skip = 1 then
   line:= ""
  fi;

 
  if  pre = 1 and minput = 0 and texit = 1 then
   for abbrev in abbrevs do
    line:= StringTools[SubstituteAll](line,op(abbrev));
   od;
  fi;

  if  pre = 1 and minput = 0 and texit = 0 then
   for abbrev in genabbrevs do
    line:= StringTools[SubstituteAll](line,op(abbrev));
   od;
  fi;

  if  StringTools[Search]("_pic[",line)>0 then
   pars := StringTools[Split](StringTools[SubString]
    (line,1+StringTools[FirstFromLeft]
    ("[",line)..StringTools[FirstFromRight]("]",line)-1),";");
   if  nops(pars) > 1 then
    line := cat("\\includegraphics[",pars[2],"]{",pars[1],"}");
   else
    line := cat("\\includegraphics[height=3in,width=4in]{",pars[1],"}");
   fi
  fi;


##
 if StringTools[Search]("HSPC_",line)>0 then
  hspc:=StringTools[RegSub]("HSPC_([^\_]*)_",line,"\\1"); line:="" fi;

  if StringTools[Search]("\\mapleplot{",line)>0 then   
   pars := StringTools[SubString]
    (line,1+StringTools[FirstFromLeft]
    ("{",line)..StringTools[FirstFromRight]("}",line)-1);
   line := cat(hspc,"\\includegraphics[height =         ",convert(evalf(216/287*picwidth,4),string),"in, width =         ",convert(picwidth,string),"in]{",pars,"}");
 hspc:="";
  fi;

  if skip = 0 and type(line,string)
     and line <>"hellobill" then
   writeline(outfile,line)
  fi;
  oline := line;

  line := readline(infile);

  if skip = 1 and line = 0 then  
   writeline(outfile,"\\end{document}")
  fi;

  od;   # end of latexit loop
 

 fclose(infile);
 fclose(outfile);

 mprint(cat(infil,"whs.tex created"));
 lfile := cat(infil,"whs");
 else lfile := infil
 fi :  ### end the if neww= yes condition

 bill := system(cat("latex ",lfile));
 if bill = 0 then
  mprint(cat(lfile,".dvi created.") )
 else
  ERROR(cat(lfile,"  A problem occurred with latex."))
 fi;

 for i from 1 to numpass-1 do
  bill :=system(cat("latex ",lfile));
  if bill = 0 then
   mprint("Pass ",i+1," to resolve references was successful.")
  else
   ERROR("Second pass to resolve references was NOT successful.")
  fi;
 od;

 close(infile);
 if convert(fxeps,string)="yes" then
  ld := f(infil,path);
  for i in ld do
   fixeps(i,Color=coler)
  od;
  ###imhere
  mprint("fixed eps files (removed their borders and recolored if Color=yes is set)");
 fi;

 if dvips <> no then
  if dvips=yes then
   bill := system(cat("dvips ",lfile))
  else
   bill := system(cat("dvips ",dvips," ",lfile));  
  fi;
  if bill = 0 then
   mprint(cat(lfile,".ps created sucessfully.") )
  else
   ERROR(cat(lfile,".ps NOT created.  A problem occurred"))
  fi;
 fi;

 if yap = yes then
  system(cat("yap -1 ",lfile))
 fi;
 mprint("finished");
end:
###end latexit


###vers
vers := proc(str,mult,no)
 global _seed;
 local n,f,offset,p,q;
 n := convert(map(StringTools[Ord],StringTools[Explode](str)),`*`);
 #_seed:=n;
randomize(n);
f := rand(1..mult);
 offset:=[seq(f(),i=1..no)];
 #_seed:=n;
randomize(n):
p := {seq(i,i=1..no)};
 q:=NULL;
 while nops(p)>1 do
  f := rand(1..nops(p));
  n := f();
  q := q,p[n];
  p := p minus {p[n]}
 od;
 q := [q,p[1]];
 [offset,q]
end:
###end vers

###xprint
xprint := proc(expr)
 if type(expr,function) and op(0,expr)=PLOT then
  print(expr);mprint("$\\!$")
 else
  (cat(" $",`latex/print`(expr),"$ "))
 fi;
end:
###end xprint

###xprint
xprint := proc(expr)
 if type(expr,function) and op(0,expr)=PLOT then
  print(expr);mprint("$\\!$")
 else
  (cat(" $",`latex/print`(expr),"$ "))
 fi;
end:
###end xprint

lxprint := proc()
 local lst,ans,l;
 if nargs=0 then mcprint("lxprint(...,argi,...) returns a catted string of the argi's
where argi is converted to latex if it is an expression
If  args[1]=\"$\" or args[1]=\"$$\" then the catted string is started and ended with the same
   and expressions are not $-signed, otherwise expressions are $-signed."); return NULL fi;
 
 lst := [args]:
 ans := "":
if lst[1]="$" or lst[1]="$$" then
for l in lst  do
 if type(l,string) then ans := cat(ans,l) else ans := cat(ans,`latex/print`(l)) fi od:
 if lst[1]="$" and lst[-1]<>"$" then ans:=cat(ans,"$")  fi;
 if lst[1]="$$" and lst[-1]<>"$$" then ans:=cat(ans,"$$") fi;
else
 for l in lst do
 if type(l,string) then ans := cat(ans,l) else ans := cat(ans," $",`latex/print`(l),"$ ") fi od:
fi;
ans;
end:

###tprint
tprint := proc(tbl)
 local i,j,m,n,b,g,tb,pos;
 if nargs>1 then pos:=args[2] else pos:="c" fi;
 m:= nops(tbl);
 n := nops(tbl[1]);
 tb:= ("\\begin{tabular}[",pos,"]{",cat(seq("l",i=1..n)),"}\n");
 for i from 1 to m do
  for j from 1 to n-1 do
   b := tbl[i][j];
   g := "\\rule{1in}":   
   if type(b,string) then
    tb := tb,(cat(b,"&"))
   elif type(b,list) then
    if nops(b)= 1  then
     tb:= tb,(cat(g,"&"))
    elif type(b[1],string) then  
     tb := tb,(cat(b[1],"&"))
    else
     tb := tb,(cat(xprint(b[1]),"&"))
    fi;
   else
    tb := tb,(cat(xprint(b),"&"))
   fi;
  od;  
  b := tbl[i][n]; #hereiamtoo
   if n = 1 and b="" then next fi; ###added2/17
   if type(b,string) then
      tb := tb,(cat(b,"\\\\\n"))
  elif type(b,list) then
   if nops(b)= 1 then  
    tb := tb,(cat(g,"\\\\"))
   elif type(b[1],string) then  
    tb := tb,(cat(b[1],"\\\\\n"))
   else
    tb := tb,(cat(xprint(b[1]),"\\\\\n"))
   fi;
  else
   tb := tb,(cat(xprint(b),"\\\\\n"))
  fi;
 od;
 (tb,"\\end{tabular}");
end:
###tprint

###lagit
#9/28
lagit:= proc()
 global LATEX_;
 LATEX_ := yes;
 whslatex(args);
 LATEX_ := no:
 NULL:
end;
###end lagit

###whslatex
whslatex := proc()
 local i,flag,lsti,s1,s2,s,k,tp,lst,j,r,p,enum,key,separ,std,forlat,tags,ce,clrs;
 global LNUM_,SPACES_,lsttmp,l,mat,LATEX_;

 if nargs>0 and type(args[1],`=`) and lhs(args[1])=Test then
  RETURN(yes)
 fi;
 forlat := proc(sboth,tp)
  local s,r, k, m, j,i,ans,opts,p,g,a,ma,ro,co;
  g := proc(r,l)
   local i;
   for i in l do
    if r=lhs(i) then
     RETURN(rhs(i))
    fi
   od;
   NULL
  end;

  s := sboth[2];
  r:= NULL:
  k := NULL:
  m := 0;  
  ans:= NULL:
  if not type(s[2],list) then
   if member(tp,{_AB,_ABlabels}) then
    ERROR(cat("The ",tp," format requires a list of alternative answers with
      each correct answer enclosed in brackets."))
   else
    ERROR(cat("The ",tp," format requires a list of alternative answers with
      the correct answer enclosed in brackets."))
   fi
  fi;

  a := g(rightanswers,sboth[1]);
  if not a=NULL then
   if type(a,list) then
    s[2]:= a
   else
    for j from 1 to nops(s[2]) do
     if a=s[2][j] then
      s[2][j]:= [a]
     fi;
    od
   fi
  fi;

  for j from 1 to nops(s[2]) do
   if type(s[2][j],list) then
    if type(op(s[2][j]),list) then
     ERROR("An answer cannot be a list.")
    else
     r := r,op(s[2][j]):
     k := k,1:
     m := m+1:
    fi
   else  
    r := r,s[2][j]:
    k:= k,0  
   fi:
  od;

  if nops([r]) < 2 then
   ERROR(cat("The ",tp," format requires a list of 2 or more alternative answers with
     the correct answer enclosed in brackets."))
  fi;
  if m = 0 then
   k := 1,seq(0,i=2..nops([k]))
  fi;
  if m > 1 and not member(tp,{_AB,_ABlabels}) then
   ERROR(cat("The ",tp," format expects only one correct answer."))
  fi;
  a := g(randomize,sboth[1]):
  if not a=NULL then  
   p := [seq(i,i=1..nops([r]))]
  else  
   p := combinat[randperm]([seq(i,i=1..nops([r]))])
  fi;
  #a := g(matsize,sboth[1]);
  #if a = false then a:= [1,nops([r])] fi;
  #ma := NULL:
  #for ro from 1 to a[1] do
  #wr := NULL:
  #for co from 1 to a[2] do
  #if (ro-1)*a[2]+co <= nops([r]) then
  #wr := wr,[r][p[(ro-1)*a[2]+co]]
  if member(tp,{_AL,_ALlabels,_AR,_AS}) then   
   for j from 1 to nops([k])  do
    if k[j]=1 then  
     ans:= r[j];  
    fi
   od:
   mprint("\\ \\\\ Circle correct answer:\\\\");
   mprint(tprint([[seq([r][p[j]],j=1..nops([r]))]]),"\\\\");
  else
   for j from 1 to nops([k])  do
    if k[j]=1 then
     ans:= ans,"::",r[j]
    fi
   od:
   mprint("\\\\ Circle \\textbf{each} correct answer:\\\\");
   mprint(tprint([[seq([r][p[j]],j=1..nops([r]))]]),"\\\\");
  fi;
  ans
 end:

 enum := "\\item \\ ":
 separ := "$\\diamond$\\hspace{2mm}";
 #separ:="\\\\\n";
 key := "";
 tags := {_TP,_AC,_AS,_AW,_AL,_AF,_AI,_AE,_AB,_ABlabels,_AL,
  _ALlabels,_AX,_AR,_AT,_ATspread,_ATcross}:
 clrs := {black,blue,navy,coral,cyan,brown,gold,green,gray,grey,
  khaki,magenta,maroon,orange,pink,plum,red,red,sienna,tan,
  turquoise,violet,wheat,white,yellow};
 std := "":
 SPACES_ := 1;
 LNUM_:=0;
 lsttmp := [args];
 lst := NULL:
 for l in lsttmp do
  if type(l,array) then
   lst := lst,Maketable(convert(l,listlist))  
  elif  type(l,function) and op(0,l)=Lineit then
   if type(op(1,l),list) then
    lst:=lst,op(op(1,l))
   else
    lst := lst,op(l)
   fi
  else
   lst:= lst,l
  fi
 od;
 lst := [lst] ;
 mprint("");
 mprint("_LATEX" );

 for i from 1 to nops(lst) do
  flag := 0;
  if i=1  then
   if type(lst[i],`=`) and lhs(lst[i])=standards then
    std := rhs(lst[i]);
    mprint(enum); next;
   else
    mprint(enum)
   fi   
  fi;
  if type(lst[i],list)and type(lst[i][1],`=`) and
     member(lhs(lst[i][1]),{pretext,aftertext}) then
   for k from 1 to nops(lst[i]) do
    if type(lst[i][k],`=`) and member(lhs(lst[i][k]),{problem,aftertext}) then
     tp := rhs(lst[i][k]);
     for j from 1 to nops(tp) do
      if type(tp[j],function) and op(0,tp[j])=Lineit then
       for k from 1 to nops([op(tp[j])]) do
        if type(op(k,tp[j]),string) then
         mprint (escape(op(k,tp[j])))
        elif type(op(k,tp[j]),list) then
         mprint(op(op(k,tp[j])))
        elif type(op(k,tp[j]),function) and member(op(0,op(k,tp[j])),{ah_}) then
         NULL
        else
         mprint(cat(" $",`latex/print`(op(k,tp[j])),"$ "))
        fi
       od:
      elif type(tp[j],string) then
       if not member(tp[j],{"td_","tr_"}) then
        mprint(escape(tp[j]))
       else
        NULL
       fi;
      elif type(tp[j],list) then
       mprint(op(escape(tp[j])))
      else
       mprint(xprint(tp[j]))
      fi
     od
    fi
   od;
   next;
  fi;

  if  type(lst[i],list) and member(lst[i][1],tags) then
   flag := 1;
   s1 := NULL:
   s2 := NULL:  
   lsti:= lst[i]:
   for k from 1 to nops(lsti) do
    if type(lsti[k],`=`) and member(lhs(lsti[k]),{brks,Alabels,
       txtboxsize,precision,funstuff,randomize,rightanswers,
       hidden,aftertext,matsize,cellcolor,tableoptions,Flabels,
       inline}) then
     s1 := s1,lsti[k]
    else
     s2 := s2,lsti[k]
    fi
   od:
  fi;

  if type(lst[i],function) and member(op(0,lst[i]),tags) then
   flag := 1:  
   s1 := NULL:
   s2 := NULL:
   tp := op(0,lst[i]):
   lsti := [tp,op(lst[i])]:
   for k from 1 to nops(lsti) do
    if type(lsti[k],`=`) and member(lhs(lsti[k]),{brks,Alabels,
       txtboxsize,precision,funstuff,randomize,rightanswers,
       aftertext,matsize,cellcolor,tableoptions,Flabels,
       inline}) then
     s1 := s1,lsti[k]
    else
     s2 :=s2,lsti[k]
    fi
   od:
  fi;

  if flag = 1 then
   s := [s2];
   if member(s[1],{_AL,_ALlabels,_AR,_AS,_AB,_ABlabels}) then
    key:= key,separ,forlat([[s1],s],lsti[1]);
   elif member(s[1],{_AC,_AF,_AE,_AI,_AW}) then
    mprint(" \\rule{1in}{.1mm}");
    if s[1]=_AW then
     if type(s[2],list) then
      s[2] := op(s[2])
     fi;
     if not type(s[2],string) then
      ERROR("The AW format requires a string of #-separated acceptable spellings.")
     fi;
     s[2] := StringTools[SubstituteAll](s[2],"#","\\#")  
    fi;
    key := key,cat(separ,s[2]);
   elif member(s[1],{_AT,_ATspread,_ATcross}) then
    r := NULL:
    for j from 1 to nops(s[2]) do
     tp := NULL:
     for k from 1 to nops(s[2][j]) do
      if type(s[2][j][k],list) then
       ce := s[2][j][k];
       if s[1]=_ATcross and nops(ce)>1 and member(ce[2],clrs) then
        if type(ce[1],string) then
         ce[1] := StringTools[SubstituteAll](ce[1],"#","\\#")  
        fi;
        tp := tp,ce[1]
       else  
        tp := tp,"\\rule{1in}{.1mm}";
        if s[1]=_ATcross and nops(ce)=1 and type(ce[1],string) then         
         ce[1]:=StringTools[SubstituteAll](ce[1],"#","\\#")  
        fi;
        key := key,cat(separ,ce[1]);
       fi;
      else
       tp := tp,s[2][j][k]
      fi:  
     od:
     r := r,[tp]
    od:
    mprint("$\\!$\\\\",tprint([r]),"\\\\")
   ####handgrade
   elif s[1]=_AX then   
    key:= key,cat(separ,lxprint(s[2]))       
   fi
  elif type(lst[i],`=`) and member(lhs(lst[i]),{brks,Alabels,
     txtboxsize,precision,funstuff,randomize,rightanswers,
     aftertext,matsize,cellcolor,tableoptions,Flabels,
     inline}) then
   NULL
  elif type(lst[i],string) then  
   mprint(escape(lst[i]))
  elif type(lst[i],function) and op(0,lst[i])=MCPIECEWISE then
   mat := op(1,lst[i]):
   mprint(tprint([seq([mat[j]],j=1..nops(mat))]))
  elif type(lst[i],array) then
   mat := convert(lst[i],listlist):
   mprint(tprint([seq([seq(mat[j,k],k=1..nops(mat[j]))],j=1..nops(mat))]))
  elif type(lst[i],function) and op(0,lst[i])=Maketable then
   mprint(tprint(op(1,lst[i])))   
  elif type(lst[i],list) then
   if i=1 then
    mprint(op(lst[i]));
   else
    mprint(op(lst[i]))
   fi
  elif type(lst[i],`=`) and lhs(lst[i])=pretext then
   if i=1 or (i=2 and std<>"") then
    if type(rhs(lst[i]),string) then
     mprint(escape(rhs(lst[i])))
    elif type(rhs(lst[i]),list) then
     for j from 1 to nops(rhs(lst[i])) do
      if type(rhs(lst[i])[j],string) then
       mprint(escape(rhs(lst[i])[j]))
      elif type(rhs(lst[i])[j],list) then
       mprint(op(rhs(lst[i])[j]))
      else
       mprint(xprint(rhs(lst[i])[j]))
      fi
     od
    else
     mprint(xprint(rhs(lst[i])))
    fi;
   else
    ERROR("pretext must be first (after standards)")
   fi;
  elif type(lst[i],function) and op(0,lst[i])=Brak then
   mprint(op(brak()))
  elif type(lst[i],function) and op(0,lst[i])=Vspace then
   mprint(op(vspace(op(1,lst[i]))))
  elif type(lst[i],function) and i > 1 and op(0,lst[i])=Lineit then
   mprint(tprint([op(1,lst[i])]))
  else if i=1 then
   if type(lst[i],function) and op(0,lst[i])=Lineit then  
    mprint(tprint([op(1,lst[i])]));
    mprint("\\\\");
   else  
    print(lst[i]);
   fi;
  else
   mprint(xprint(lst[i]))
  fi
 fi;
 od:
 if member(SPACES_,{seq(i,i=1..10)}) then
  mprint("\\vspace{",SPACES_*12,"pt}")
 fi:
 mprint("_XETAL");
 mprint("_KEY");
 mprint(std);
 if key=NULL then key:=" " fi:
  
 mprint(tprint([seq([lxprint(key[i])],i=1..nops([key]))],"t"));
 mprint("_YEK");
end:
###end whslatex

###rootwork
rootwork := proc(rootname,path)
 local infile,outfile,line,MASTER,defaults,docstyle,preamble,pkgs,
       abbrevs,styles,dvips,yap,numpass,help,files,mfiles,f,opts,newroot,title,
       author,frontpiece,rawtitlepage,file,i,bline,fonts,lengths,purpose,mkindex,
       contents,heads,stylelist,extra,names,fontsize,bill;
 defaults := Newroot=yes,Numpass=2,Docstyle=DOCSTYLE,
       Pkgs=PKGS,Preamble=PREAMBLE,Abbrevs=ABBREVS,
       Styles=PSTYLE,Dvips=yes,Yap=no,
       Help=no,Title="",Author="",Files=[],Frontpiece="",
       Fonts="",Lengths="",Purpose="notes",Mkindex=no,Contents=no,Pagestyle=plain,
       Extra="",Names=[],FontSize="",Titlepage="":
 opts := subs([ op(select(type,[args],`=`)),defaults],
    [Newroot,Numpass,Docstyle,Pkgs,Preamble,Abbrevs,Styles,Dvips,Yap,Help,Title,
    Author,Files,Frontpiece,Fonts,Lengths,Purpose,Mkindex,Contents,Pagestyle,Extra,
    Names,FontSize,Titlepage]);
 newroot := opts[1]:
 numpass := opts[2]:
 docstyle := opts[3]:
 pkgs := opts[4]:
 preamble := opts[5]:
 abbrevs := opts[6]:
 styles := opts[7]:
 dvips := opts[8]:
 yap := opts[9]:
 help := opts[10]:
 title := opts[11]:
 author := opts[12]:
 mfiles := opts[13]:
 files := NULL: for f in mfiles do if type(f,string) then files := files,f fi od:
 files:= [files]:
 frontpiece := opts[14]:
 fonts := opts[15]:
 lengths := opts[16]:
 purpose := opts[17]:
 mkindex := opts[18]:
 contents := opts[19]:
 heads := opts[20]:
 extra := opts[21]:
 names := opts[22]:
 fontsize := opts[23]:
 rawtitlepage:=opts[24]:

 if fonts<>"" then
  if fonts=sanserif then
   fonts:=SSFONTS
  fi
 fi;

 preamble := cat(fonts,LENGTHS,MACROS):

 if purpose=amspaper then
  docstyle:=DOCSTYLEAMS:
  pkgs := PKGSAMS:
  styles := PSTYLEAMS:
  preamble := cat(fonts,preamble,AMSMACROS):
 fi;

 if fontsize<>"" then
  docstyle:=StringTools[Substitute](docstyle,"11pt",fontsize)
 fi;

 preamble:= cat(preamble,extra);

 if mkindex=yes then
  pkgs :={makeidx} union pkgs
 fi;
 pkgs:= convert(pkgs,string);

 styles := [op({op(styles)} union {op(extrastyles)})];

 if help = yes then
  mprint(cat(convert(VERSION,string)," rootwork(\"rootname\",\"path\",Options)
     where rootname is the name you want for the rootfile
     and path is the path to the directory with the latex files.
     Brief instructions:
     Export your worksheets to latex and process them with latexit.
     Make a rootfile with rootwork, and add the files as includes to make a
     large document.
   Options:
    Newroot=yes  set to no if you don't want to redo the rootfile.
    Files=[]  set to a nonempty list of files you want to include in the rootfile.
    Numpass=2  set to the number of times to latex the root file.
    Titlepage=\"\"  set to whatever you want just after begin{document}
    usually a title page, otherwise set the Title Author and Frontpiece below
    if you want a generic titlepage  
    Title=\"\"  set to a non empty string if you want a title page.
      Author\"\"  set to the name of the author for the title page.
    Frontpiece=\"\"  set to the name of a graphic file (eps or jpg).
    Dvips =yes  gives a postscript file
    Fonts=regular  set to sansserif for MS sans serif
    Lengths=""  set to pageheight, pagewidth, etc
    Amspaper=no set to yes if the documentstyle is amsart
    Mkindex=yes  creates an idx file of words in Files marked with
      Character style index
    Contents=yes gives a table of contents
    Pagestyle=headings set to none if you don't want that."));
  RETURN(NULL)
 fi;

 currentdir(path);

 MASTER:= cat(rootname,".tex");

 if newroot = yes then
  try
   fopen(MASTER,WRITE,TEXT)
  catch "file already open":
   fclose(MASTER);
   fopen(MASTER,WRITE,TEXT);
  end try;
  writeline(MASTER,cat("\\documentclass",docstyle)) ;
  writeline(MASTER,cat("\\usepackage",pkgs));
  writeline(MASTER,preamble);
  writeline(MASTER,cat("\\pagestyle{",heads,"}"));
  
  if mkindex = yes then
   if numpass < 2 then
    numpass:=2
   fi;
   writeline(MASTER,"\\makeindex")
  fi:

  writeline(MASTER,"\\begin{document}");
  if rawtitlepage<>"" then writeline(MASTER,rawtitlepage);
  title:="" fi:
  if  title <> "" then
   writeline(MASTER,"\\begin{titlepage}
    \\vspace*{1in}
    \\begin{center}");
   writeline(MASTER,cat("{\\Huge\\bf ",title,"}\\\\"));
   writeline(MASTER,"\\bigskip");

   if author<>"" then
    writeline(MASTER,cat("{\\sl ",author,"}\\\\"));
   fi;

   if frontpiece<>"" then
    if type(frontpiece,string) then
     writeline(MASTER,
      cat("\\includegraphics[width=4in,height=3in,angle=-90]{",frontpiece,"}\\\\"))
    elif type(frontpiece,list) and nops(frontpiece)=3 then
     writeline(MASTER,
       cat("\\includegraphics[width=",frontpiece[1],"in,height=",
       frontpiece[2],"in,angle=-90]{",frontpiece[3],"}\\\\"))
    elif type(frontpiece,list) and nops(frontpiece)=4 then
     writeline(MASTER,cat("\\includegraphics[width=",
       frontpiece[1],"in,height=",frontpiece[2],"in,angle=",
       frontpiece[3],"]{",frontpiece[4],"}\\\\"))
    else
     close(MASTER);
     ERROR("Problem with frontpiece")
    fi
   fi;

   writeline(MASTER,"\\bigskip
     {\\today}
     \\end{center}
     \\end{titlepage}")
  fi;
  if contents=yes then
   numpass:=max(numpass,2);
   writeline(MASTER,"\\tableofcontents")
  fi;

  writeline(MASTER,"\\end{document}");
  close(MASTER);
  mprint("rootfile created");
 fi;   # end newroot=yes

 if nops(files)>0 then
  stylelist:= getstyles(rootname,files,path);
  try
   fopen(MASTER,READ,TEXT)
  catch "file already open":
   fclose(MASTER);
   fopen(MASTER,READ,TEXT);
  end try;
 ####

 outfile:=cat(rootname,"tmp.tex");
 try
  fopen(outfile,WRITE,TEXT)
 catch "file already open":
  fclose(outfile);
  fopen(outfile,WRITE,TEXT);
 end try;

 line := readline(MASTER);
 while StringTools[Search]("begin{document}",line)=0 do
  line:=readline(MASTER);
 od;
 writeline(outfile,stylelist);

 writeline(outfile,line);
 line := readline(MASTER);
 bline:= NULL:
 while StringTools[Search]("end{document}",line)=0 do
  bline:=bline,line;
  line:=readline(MASTER);
 od;


 for i from 1 to nops(mfiles) do
  if type(mfiles[i],list) then bline:=bline,op(mfiles[i])
  elif convert(StringTools[Search](cat("{",mfiles[i],"}"),[bline]),`+`)=0 then
   rootify(mfiles[i],path);
   if i <= nops(names) and names[i]<>"" then
    bline := bline,cat("\\section{",names[i],"}")
   fi;
   bline := bline,cat("\\include{",mfiles[i],"}")
  fi;
 od;
 if bline<>NULL then
  writeline(outfile,bline)
 fi;

 if mkindex=yes and newroot=yes then
  writeline(outfile,"\\addtocontents{toc}{\\hspace{-.3in} \\textbf{Index}
    \\dotfill \\thepage}");
  writeline(outfile,cat("\\include{",rootname,"ind}"))
 fi;
 writeline(outfile,line);
 fclose(outfile):
 fclose(MASTER);
 FileTools[Remove](MASTER);
 FileTools[Rename](outfile,MASTER);
 #system(cat("del ",MASTER));
 #system(cat("ren ",outfile," ",MASTER));
 mprint("added the files",files);
 fi;

 if numpass>0 then
  if system(cat("latex ",rootname))=0 then
   mprint(cat(rootname,".dvi created"))
  else
   mcpint("Problem with latex")
  fi;
  if mkindex=yes then
   system(cat("makeindex ",rootname,".idx"));
   if FileTools[Exists](cat(rootname,"ind.tex")) then     
    FileTools[Remove](cat(rootname,"ind.tex"))
   fi;
   FileTools[Rename](cat(rootname,".ind"),cat(rootname,"ind.tex"))
  fi;
  for i from 1 to numpass-1 do
   if system(cat("latex ",rootname))=0 then
    mprint("pass ",i+1," to resolve references completed.")
   else
    mprint("Problem with latex")
   fi
  od
 fi;

 if dvips <> no then
  if dvips=yes then
   bill := system(cat("dvips ",rootname))
  else
   bill := system(cat("dvips ",dvips," ",rootname));  
  fi;
  if bill=0 then
   mprint("postscript file created.")
  else
   print(bill,dvips);
   mprint("Problem with dvips")
  fi
 fi;
end:
###end rootwork

###  begin htmltools
###glosub
glosub := proc(infile,path)
 local file,files,line,outfile,f,defaults,s,opts,help,suffix,substitutions,
       force,ln,all,between,after,a,before,b,safter,sbefore,regular,show,maxlns,
       maxfls,fcnt,cnt,contains;
 defaults:=Help=no,Between=[0,1000000000],All=yes,
Regular="",
Substitutions=[[StringTools[Char](13),""]],
Suffix="",Force=no,After="",Before="alalalalalal_",Show="no",Maxlines=10,
Maxfiles=10,Contains="";
 opts:= subs([     op(select(type,[args],`=`)),defaults],[Help,Substitutions,Suffix,Force,Between,All,
After,Before,Regular,Show,Maxlines,Maxfiles,Contains]);
 help:=opts[1];
 substitutions:=opts[2];
 suffix:=opts[3]:
 force:=opts[4]:
 between:=opts[5]:
 all:=opts[6]:
 after:=opts[7]:
 before:=opts[8]:
 regular:=opts[9]:
 show:=opts[10]:
 maxlns:=opts[11]:
 maxfls:=opts[12]:
 contains:=opts[13]:
 safter:= after;
 sbefore:=before;
 a := no;
 b := yes;
 if help = yes then mprint(
"Use glosub(\"worksheet\",\"c:/tmp/folder\",Suffix=\".html\",
    Substitutions=[[\"bill\",\"sam\"],[\"rule{1in}\",\"rule{.2in}\"]);
    to make the global substitution of sam for bill and rule{.2in} for rule{1in}
    in all the files in c:/tmp/folder which start with worksheet and end with
    the suffix .html
    Note 1: Exercise care with the use of this word, lest ye make destructive
    changes.
    Note 2: By choosing the option Show=yes (see below), you can look at lines
    in files before making substitutions.  
   Options:
   Substitutions=[[\"StringTools[Char](13)\",\"\"]]  replace each occurence of
   Char(13) (cntrl M) with the empty string. Change to a list of lists of substitutions.
   Suffix=\"\"  set to \".html\", to make changes in all files ending with .html and
   beginning with worksheet. Note: to process a single file set worksheet to the
   full name including suffix.
   Force=no change to yes to force the substitution (otherwise glosub bails if it encounters an <html> at the top.
   Between=[1,1000000000] change this to [5,20] to substitute in the lines 15 to 20
   After=\"\"   change this to \"begin{document}\" to begin substitution after the
   first line containing the string begin{document}
   Before=\"alalalalalala_\"  change to a string after which you dont want substitutions made  
   All=yes  change to no if the substitution occurs only with the first occurrence of the pattern in the line.
   Regular=\"\" use this to make general substitutions with regular expressions.
     For example to remove all the color assignments in the html export of a worksheet
     set Regular=[[\"color=\\\"([#0-9A-Xa-x]+)\\\"\" = \"color=\\\"\\\"]]
   Contains=\"\"  set to a regular expression to select files containing a substring
   matching that regular expression.
   Show=no   set to yes if you just want to show lines in files
   Maxlines=10  if Show=yes shows the first 10 lines satisfying Between and After
   options.
   Maxfiles=10  if Show=yes shows lines in the first 10 files starting with worksheet
   and ending with Suffix");
RETURN(NULL) end if;
 
 f := proc(nm,path)
  local st,ld,out,g,n;
  n:= length(nm);
  g := proc(s)
    if contains<>"" then if StringTools[RegMatch](contains,s) then
     RETURN(true) else RETURN(false) fi fi;
    if suffix="" and s<>nm then RETURN(false) fi;
   if s=nm and suffix="" then RETURN(true) fi;
   if length(s) < length(suffix) then RETURN(false) fi;
   if substring(s,-length(suffix)..-1)=suffix and substring(s,1..n)=nm then
    true
   else
    false
   fi
  end;    
  select(g,FileTools[ListDirectory](path));
 end:  

 currentdir(path);
 files := f(infile,path);
  if files=[] then mprint("No files starting with ",infile," and ending with ",suffix);
  RETURN(NULL) fi;
  fcnt:=0;
  for file in files do
  fcnt:=fcnt+1;
  if show=yes and fcnt > maxfls then RETURN(NULL) fi;
  after := safter;
  before:=sbefore;
  a := no;
  b := yes;
  try
   fopen(file,READ,TEXT)
  catch "file already open":
   fclose(file);
   fopen(file,READ,TEXT);
  end try;

  outfile := cat("tmp_",file);
   if FileTools[Exists](outfile) then
   fclose(outfile);
   FileTools[Remove](outfile) fi;
    try
   fopen(outfile,WRITE,TEXT)
  catch "file already open":
   fclose(outfile);
   fopen(outfile,WRITE,TEXT);
  end try;
  if show=yes then
  mprint(StringTools[PadLeft](convert(fcnt,string),6),".  ",file," ----- ") fi;
  line := readline(file);
  if after="" then a:=yes fi;
  if suffix=".html" then
  if line="<html>" and force=no then
   fclose(outfile);
   fclose(file);
   FileTools[Remove](outfile);
   mprint(file," not processed. <html> at top.");
   next
  elif line="<html>" then
   line:="";
  else  
   writeline(outfile,"<html>")
  fi;
  fi;
  ln := 0;
  cnt:=0;
  while line<>0 do
   ln := ln+1;
   if StringTools[Search](after,line)>0 then a := yes; fi;
   if StringTools[Search](before,line)>0 then b := no; fi;
   if ln >= between[1] and ln <= between[2] and a =yes and b=yes then
   if show=yes and cnt < maxlns then mprint(StringTools[PadLeft](convert(ln,string),3),". ",line); cnt:= cnt+1;
   else
   if type(regular,list) then
   for s in regular do
      if line <> "" then line:=StringTools[RegSubs](s[1],line) fi od:
   fi:
   for s in substitutions do
        if all=yes then
        line:= StringTools[SubstituteAll](line,s[1],s[2])
        else
        line:= StringTools[Substitute](line,s[1],s[2]) fi
     od;
   fi;
   fi; #end  show
   if line<>"" then
    writeline(outfile,line)
   fi;
   line:=readline(file);
   
  od;
   
  fclose(outfile):
  fclose(file);
  FileTools[Remove](file);
  FileTools[Rename](outfile,file);
 mprint(file);
 od;
 if show<>yes then
 mprint("substitutions made") fi;
end:
###end glosub

###htmlit
htmlit := proc(infile,path)
 local infil,outfile,omit,line,bkmrks,l,r,b,opts,a,c,defaults,glsb,help,title;
 defaults:=Help=no,Title="",Glosub=yes;
 opts:= subs([ op(select(type,[args],`=`)),defaults],[Help,Title,Glosub]);
 help:=opts[1]:
 title:=opts[2]:
 glsb:=opts[3]:

 if help=yes then
  mprint("htmlit(\"worksheet\",\"path\")  removes dl indentation from
     worksheet1.html, the preformatting tags <pre > and </pre > in textoutput,
     and removes any html in an *OMIT/*TIMO block.  It also removes links to
     sections in such a block from worksheetTOP.html
  Options:   
   Help=yes will display this message.
   Title=\"\" Replace with the title of the worksheet in its TOC.
   Glosub=yes  change to no if you don't want glosub.");
  RETURN(NULL)
 fi;

 infil:= cat(infile,"1.html");
 bkmrks := NULL:

 currentdir(path);

 if glsb=yes then
  glosub(infile,path,Suffix=".html")
 fi;

 outfile := cat("tmp_",infil);

 try
  fopen(infil,READ,TEXT)
 catch "file already open":
  fclose(infil);
  fopen(infil,READ,TEXT);
 end try;
 try
  fopen(outfile,WRITE,TEXT)
 catch "file already open":
  fclose(outfile);
  fopen(outfile,WRITE,TEXT);
 end try;

 omit := no;
 line := readline(infil);
 writeline(outfile,line);
 line := readline(infil);
 while line<>0 do
  if StringTools[Search]("</html>",line)>0 then
   writeline(outfile,line);
   fclose(outfile);
   fclose(infil);
   FileTools[Remove](infil);
   FileTools[Rename](outfile,infil);

   outfile := cat("tmp_",infile,"TOC.html");
   infil:=cat(infile,"TOC.html");
   try
    fopen(infil,READ,TEXT)
   catch "file already open":
    fclose(infil);
    fopen(infil,READ,TEXT);
   end try;
   try
    fopen(outfile,WRITE,TEXT)
   catch "file already open":
    fclose(outfile);
    fopen(outfile,WRITE,TEXT);
   end try;
   line:=readline(infil);
   while line<>0 do
    l:=1;
    if StringTools[RegMatch](
       "MapleAutoBookmark1\"
       target=\"Content\">([a-zA-Z0-9_.\\)\\(\\ ]+)</a",line,'a','c')
       and opts[2]<>"" then
     line:=StringTools[Substitute](line,c,title)
    fi;
    if StringTools[Search]("MapleAutoBookmark",line)>0 then
     l:=0;
     for b in [bkmrks] do
      if StringTools[Search](b,line)>0 then
       l:= 1+1;
      fi;
     od;
     if l > 0 then
      l:=1
     fi;
    fi;
    if l=1 and line<>"" then
     writeline(outfile,line)
    fi;
    line:=readline(infil)
   od;
   fclose(outfile);
   fclose(infil);
   FileTools[Remove](infil);
   FileTools[Rename](outfile,infil);
   mprint(cat(infil," filtered"));
   RETURN(NULL)
  fi;

  if StringTools[Search]("_OMIT",line)>0 then
   omit := yes;
   line:= readline(infil);
   next
  fi;
  if StringTools[Search]("_TIMO",line)>0 then
   omit := no;
   line := readline(infil);
   next
  fi;

  if omit=no  then
   if StringTools[Search]("MapleAutoBookmark",line)>0 then
      StringTools[RegMatch]("MapleAutoBookmark[0-9]+\"",line,'r');
    bkmrks := bkmrks,r;  
   fi;
   line:=StringTools[SubstituteAll](line,"<pre>","");
   line:=StringTools[SubstituteAll](line,"</pre>","");
   line:=StringTools[SubstituteAll](line,"<dl>","");
   line:=StringTools[SubstituteAll](line,"</dl>","");
   if line<>"" then
    writeline(outfile,line)
   fi;
  fi;
  line:=readline(infil);
 od;

end:
###end htmlit

###mkhtmlindex
mkhtmlindex := proc(root,files,path)
 local file,line,outfile,f,index,index_mark,num,k,bkmk,
       billy,b,tfile,sline,help,opts,defaults;
 defaults:=Help=no;
 opts:= subs([ op(select(type,[args],`=`)),defaults],[Help]);
 help:=opts[1];

 if help=yes then
  mprint("makehtmlindex(\"rootname\",[file1,file2..],path)
     where rootname is the name you have chosen for the rootfile
     [file1,...] is the list of html files in the document.  This word is used by
     htmlrootwork.");  
  RETURN(NULL);
 fi;

 currentdir(path);
 outfile := cat(root,"_index.html");
 num:= 1000;
 index_mark := "<b><font color=\"#008000\">":
 index:=table([]);

 f := proc(a,b)
  if member(StringTools[LexOrder](op(a)[2],op(b)[2]),{-1,0}) then
   true
  else
   false
  fi
 end;

 try
  fopen(outfile,WRITE,TEXT)
 catch "file already open":
  fclose(outfile);
  fopen(outfile,WRITE,TEXT);
 end try;

 writeline(outfile,"<html>");
 writeline(outfile,"<head>");
 writeline(outfile,cat("<title>",outfile,"</title>"));
 writeline(outfile,cat("<!-- Created ",StringTools[FormatTime](%c)," -->"));
 writeline(outfile,"</head>");
 writeline(outfile,"<body bgcolor=\"FFFFFF\">");
 writeline(outfile,"<basefont size=\"3\">");
 writeline(outfile,"<table><tr><td>");
 writeline(outfile,"<h2>Index</h2>");
 writeline(outfile,"</td></tr><tr><td>");
 writeline(outfile,"<ul>");

 for file in files do
  file := cat(file,"1.html");
  tfile:= cat("tmp_",file);
  try
   fopen(file,READ,TEXT)
  catch "file already open":
   fclose(file);
   fopen(file,READ,TEXT);
  end try;

  try
   fopen(tfile,WRITE,TEXT)
  catch "file already open":
   fclose(tfile);
   fopen(tfile,WRITE,TEXT);
  end try;

  line:= readline(file);
  while line<> 0 do
   if   StringTools[SubString](line,1..length(index_mark))=index_mark then
    sline := StringTools[Delete](line,1..length(index_mark));
    k:=StringTools[Search]("</font>",sline);
    num := num+1;
    if k>0 then
     bkmk:=StringTools[SubString](sline,1..k-1):
    else
     bkmk:=StringTools[SubString](sline,1..min(length(sline),20))
    fi;
    index[[num,bkmk]]:=
      cat("<li><font size=\"-2\"><a href=\"",file,"#MapleAutoBookmark",
        num,"\" target=\"Content\">",bkmk,"</a></font>");
    writeline(tfile,cat("<a name=\"MapleAutoBookmark",num,"\" />"));
   fi;
   writeline(tfile,line);
   line:=readline(file);
  od;
  fclose(file);
  fclose(tfile);
  FileTools[Remove](file);
  FileTools[Rename](tfile,file);
 od;

 billy := sort([indices(index)],f);
 for b in billy do
  writeline(outfile,index[op(b)])
 od;

 writeline(outfile,"</ul>");
 writeline(outfile,"</table>");
 writeline(outfile,"</html>");
 fclose(outfile);
 mprint(outfile," created");
end:
###end mkhtmlindex

###htmlrootwork
htmlrootwork := proc(root,path)
 local file,line,outfile,opts,defaults,help,index,files;
 defaults:=Help=no,Index=no,Files=[];
 opts:= subs([ op(select(type,[args],`=`)),defaults],[Help,Index,Files]);
 help:=opts[1];
 index:=opts[2];
 files:=opts[3];

 if help=yes then
  mprint("htmlrootwork(\"rootname\",\"path\",Files=[\"file1\",\"file2\",..])
     where rootname is the name you have chosen for the rootfile, path is
     the path to the folder containing the html files, and
     [file1,...] is the list of html files in the document.  These should be
     processed in advance with htmlit.
  Options:
   Help=no  change to yes to get this message.
   Index=no  change to yes to create an index.");
  RETURN(NULL);
 fi;

 if files=[] then
  ERROR("Add the option Files=[file1,file2,...] to the input line.")
 fi;

 currentdir(path);

 if index=yes then
  mkhtmlindex(root,files,path);  
  files:= [op(files),"index"]
 fi;

 outfile := cat(root,"TOC.html");

 try
  fopen(outfile,WRITE,TEXT)
 catch "file already open":
  fclose(outfile);
  fopen(outfile,WRITE,TEXT);
 end try;

 writeline(outfile,"<html>");
 writeline(outfile,"<head>");
 writeline(outfile,cat("<title>",outfile,"</title>"));
 writeline(outfile,cat("<!-- Created ",StringTools[FormatTime](%c)," -->"));
 writeline(outfile,"</head>");
 writeline(outfile,"<body bgcolor=\"FFFFFF\">");
 writeline(outfile,"<basefont size=\"3\">");
 writeline(outfile,"<h2>Contents</h2>");

 for file in files do
  if file = "index" then
   file := cat(root,"_index.html")
  else
   file := cat(file,"TOC.html")
  fi;
  try
   fopen(file,READ,TEXT)
  catch "file already open":
   fclose(file);
   fopen(file,READ,TEXT);
  end try;

>   
  line := readline(file);
  while StringTools[Search]("<table",line)=0 do
   line := readline(file)
  od;
  writeline(outfile,line);
  line := readline(file);
  while StringTools[Search]("</table",line)=0 do
   #if StringTools[Search]("MapleAutoBookmark1\"",line)=0 then
   writeline(outfile,line);
   #fi;
   line:=readline(file);
  od;
  writeline(outfile,line);
  fclose(file);
 od;
 writeline(outfile,"</body>");
 writeline(outfile,"</html>");
 fclose(outfile);

>   
 outfile:=cat(root,".html");
 try
  fopen(outfile,WRITE,TEXT)
 catch "file already open":
  fclose(outfile);
  fopen(outfile,WRITE,TEXT);
 end try;

 writeline(outfile,"<head>");
 writeline(outfile,cat("<title>",cat(root,".html"),"</title>"));
 writeline(outfile,cat("<!-- Created ",StringTools[FormatTime](%c)," -->"));
 writeline(outfile,"</head>");
 writeline(outfile,"<basefont size=\"3\">");
 writeline(outfile,"<frameset cols=\"20%,*\">");
 writeline(outfile,cat("<frame src=",cat(root,"TOC.html"),"     
  name=\"TableOfContents\"/>"));
 writeline(outfile,cat("<frame src=",cat(files[1],"1.html")," name=\"Content\" />"));
 writeline(outfile,"<noframes>");
 writeline(outfile,"Sorry, this document requires that your browser support frames.");
 writeline(outfile,cat("<a href=",cat(root,".html"),
  " target=\"Content\">This   link</a>"));
 writeline(outfile,"will take you to a non-frames presentation of the document.");
 writeline(outfile,"</noframes>");
 writeline(outfile,"</frameset>");
 writeline(outfile,"</basefont>");
 writeline(outfile,"</html>");
 fclose(outfile);
 mprint("root file created. ",outfile);
end:

>    ###end htmlrootwork

>    ### begin mwstools
#check a utility used in mwswrite, mwsit, unmwsit, and mwsrootwork

>    ###CHECK_
CHECK_ := proc(line)
 nops([StringTools[SearchAll]("{",line)])-nops([StringTools[SearchAll]("\\{",line)])
 -(nops([StringTools[SearchAll]("}",line)])-nops([StringTools[SearchAll]("\\}",line)])) end;
###end CHECK_

###mwswrite
mwswrite := proc()
 local infile,outfile,pgph,line,p,phs,i,opts,defaults,
       wrt,tags,help,path,infil, lst,nobkmks,a,b,c,checkbracs,outfile2;
 defaults:=Help=no, Write=no,Path="",Tags=["USTY","SECT","CSTY","MARK"],
       File="", List="",Remove_Bookmarks=no,Check_Brackets=no,Outfile="";
 opts:= subs([ op(select(type,[args],`=`)),defaults],
       [Help,Write,Path,Tags,File,List,Remove_Bookmarks,Check_Brackets,Outfile]);
 help:=opts[1]:
 wrt:=opts[2]:
 path := opts[3];
 tags:=opts[4]:
 infil:=opts[5]:
 lst:=opts[6]:
 nobkmks:=opts[7];
 checkbracs:=opts[8];
 outfile2:=opts[9];

 if wrt=yes then
  if infile="" then
   ERROR("Need a file name to write to.")
  else
   if StringTools[SubString](infil,-4..-1)<>".mws" then
    infile:=cat(infil,".mws")
   else
    infile:= infil
   fi;
   outfile := cat("tmp_",infile)
  fi
 fi;

 if lst<>"" then
  pgph:= cat(op(lst))
 elif infil<>"" then
  if path <> "" then
   currentdir(path)
  fi;
  if StringTools[SubString](infil,-4..-1)<>".mws" then
   infile:=cat(infil,".mws");
   outfile:=cat("tmp_",infile)
  else
   infile:= infil;
   outfile := cat("tmp_",infile);
  fi;

  try
   fopen(infile,READ,TEXT)
  catch "file already open":
   fclose(infile);
   fopen(infile,READ,TEXT);
  end try;

  pgph:= readline(infile);
  line:=readline(infile);
  while line<>0 do
   if length(line)>70 then
    if StringTools[SubString](line,71..72)="\\+" then
     line := StringTools[SubString](line,1..70)
    fi
   fi;
   pgph := cat(pgph,line);
   line := readline(infile);
  od;
  
  fclose(infile);
 else
  ERROR("Need a file name or a list of strings")
 fi;

 if nobkmks=yes then  
  pgph:= mwswrite(List=[pgph],Tags=["PARA"]);
  phs := NULL;
  for line in pgph do
   if StringTools[RegMatch](cat("{",PARA_," [0-9]+ (\"\" 0 \"[#-~ ]*\")"),line,'a','b') then
    c := StringTools[Substitute](a,b,"\"\" 0 \"\"");
    line:=StringTools[Substitute](line,a,c)
   fi;
   phs := cat(phs,line);
  od;

  pgph := phs;
 fi;

 pgph:=StringTools[Split](pgph,"{");
 phs := NULL: line:=NULL;

 for i from 2 to nops(pgph) do
  p := pgph[i];
  if member(StringTools[SubString](p,1..4),tags) then
   if checkbracs=yes then
    mprint(CHECK_(line),"  ",StringTools[SubString](line,2..5))
   fi;
   phs := phs,line;
   line:= cat("{",p);
  else
   line := cat(line,"{",p)
  fi;
 od;
 if checkbracs=yes then
  mprint(CHECK_(line),"  ",StringTools[SubString](line,2..5))
 fi;
 phs := [phs,line];

 if wrt = yes then
  try
   fopen(outfile,WRITE,TEXT)
  catch "file already open":
   fclose(outfile);
   fopen(outfile,WRITE,TEXT);
  end try;
  for p in phs do
   writeline(outfile,p)
  od;

  fclose(outfile);
  if outfile2="" then
   FileTools[Remove](infile);
   FileTools[Rename](outfile,infile);
  else
   if outfile<>outfile2 then  
    FileTools[Rename](outfile,cat(outfile2,".mws"))
   fi
  fi;
  NULL;
 else
  phs
 fi;

end:
###mwswrite

>   

>   

>   

>    ####mwsit
mwsit := proc(infile,path)
 local pgph,outfile,infil,l,s,n,m,t,r,a,b,c,i,bk,sline,line,tline,
       phs,defaults,opts,help,bookmarks,getbookmarks,j,txt,bill,nt,
       bookmarkstyles,outfile2,bklen;
 defaults:=Help=no,BookMarkStyles=["index","word","bookmark"],
 Outfile="",BookMarkLength=37;
 opts:= subs([ op(select(type,[args],`=`)),defaults],
       [Help,BookMarkStyles,Outfile,BookMarkLength]);
 help:=opts[1]:
 bookmarkstyles:=opts[2]:
 outfile:= opts[3]:
 bklen:=opts[4];

 if evaln(MARK_)=MARK_ then LAdefaults() fi;
 if help=yes then
  mprint("mwsit(\"worksheet\",\"path\") Reconstructs the bookmarks of
      the worksheet located in path. Sections and text marked with \"index\"
      character style are bookmarked.
      Use unmwsit(\"worksheet\",\"path\") to remove all bookmarks from
      the worksheet.
  Options (with defaults):   
   Help=no  Help=yes will display this message.
   Outfile=\"\"  Outfile = \"bill\" writes the worksheet to bill.mws in path.
   BookMarkStyles=[\"index\",\"bookmark\",\"word\"] is the list of characterstyles
    that bookmarks are in.
   BookMarkLength=37:  the first 37 characters of a bookmark are copied." );
  RETURN(NULL)
 fi;

 infil:= cat(infile,".mws");

 #if infil=outfile then ERROR("This is the default.") fi;
 pgph := NULL:

 currentdir(path);

 pgph:= mwswrite(File=infile,Tags={"PARA","CSTY"});
 phs:= NULL;
 line := NULL:
 bookmarks:= NULL:
 getbookmarks:= false;
 for s in pgph do
  if StringTools[RegMatch]("CSTYLE \"([a-z]*)\" -1 ([0-9]+) ",s,'a','b','c') then
   if member(b,bookmarkstyles) then
    bookmarks := bookmarks,c   
   fi
  fi;
  
  if StringTools[SubString](s,2..5)="PARA" then
   n := NULL;
   for j from 1 to nops([bookmarks]) do
    txt := cat("TEXT ",convert([bookmarks][j],string));
    nt:= [StringTools[SearchAll](txt,s)];
    if nops(nt)>0 then
     n := n,op(nt)
    fi;
   od;
   if n<>NULL then
    n := [op(sort({n})),length(s)];
    bk:=NULL:
    for j from 1 to nops([bookmarks]) do
     txt := cat("TEXT ",convert([bookmarks][j],string));
     for i from 1 to nops(n)-1 do
      bill:= StringTools[RegMatch](cat(txt," [0-9]+ \"([#-~ ]*)\""),
           StringTools[SubString](s,n[i]..n[i+1]),'r','t');
      if bill then
       if bk<>NULL then
        bk := bk,t
       else
        bk := t;
       fi;
      fi;
     od;
    od;
    if StringTools[RegMatch](
      "(PARA [-]*[0-9]+ \"[> ]*\" [0-9]+ )\"([#-~ ]*)\"",s,'a','b','c') then
     if c <> "" then
      c := StringTools[Split](c,"|");
      if bk <> NULL then
       bk := op(c),bk
      else
       bk := op(c)
      fi
     fi
    fi;

    bk := sort([op(map(StringTools[Trim],{bk}))],lexorder);
    bk := map(StringTools[SubString],bk,1..bklen); #limit the length of a bookmark
    bk := StringTools[Join](bk," | ");

    s := StringTools[Substitute](s,a,cat(b,"\"",bk,"\""));
   fi;
  fi;
  phs := phs,s;
 od;

 phs:= mwswrite(List=[phs],Tags=["CSTY","SECT","MARK"]);

 pgph:=NULL:
 for line in phs do
  if StringTools[RegMatch](
     cat("(SECT [0-9]+ {",PARA_," [0-9]+ \"\" 0 )\"[#-~ ]*\" {",
       TEXT_," ([-0-9 ]+) \"([#-~ ]*)\""),
       line,'a','b','c','d') then
   line := StringTools[Substitute](line,a,
     cat(b,"\"",StringTools[Trim](d),"\" {TEXT ",c," \"",d,"\""));
  fi;
  pgph:=pgph,line;
 od;

 if outfile="" then
  mwswrite(List=[pgph],Path=path,File=infil,Write=yes);
  mprint(cat(infil," bookmarked."));
 else
  mwswrite(List=[pgph],Path=path,Outfile=outfile,Write=yes);
  mprint(cat(outfile," bookmarked."));
 fi;
end:
####end mwsit


#removes bookmarks from infil

>    ###unmwsit
unmwsit := proc(infil,path)
local defaults,opts,help;
defaults:=Help=no;
opts:= subs([ op(select(type,[args],`=`)),defaults],
[Help]);
help:=opts[1]:
if help=yes then mprint(
"unmwsit(\"worksheet\",path) removes the bookmarks from worksheet");
RETURN(NULL) fi;
 
mwswrite(File=infil,Write=yes,Path=path,Remove_Bookmarks=yes);
mprint(cat("bookmarks removed from ",infil));
end:
###end unmwsit

>   
#list section in a worksheet.
###show_sections
show_sections := proc(file,path)
 local junk,j,oc,a,b,c,d,e,defaults,opts,help;
 defaults:=Help=no;
 opts:= subs([ op(select(type,[args],`=`)),defaults],[Help]);
 help:=opts[1]:
 if help=yes then
  mprint(
     "show_sections(\"worksheet\",path) lists the sections in path/worksheet.
     closed sections are marked with a +");
  RETURN(NULL)
 fi;
 oc["0"]:= "  ":
 oc["1"]:="+ ":

 junk:=mwswrite(File=file,Path=path,Tags=["SECT"]):
 for j in junk do
  if StringTools[RegMatch](
     cat("(SECT ([0-9]+) {",PARA_,
     " [0-9]+ )\"\" 0 \"[#-~ ]*\" {",TEXT_," ([-0-9 ]+)      \"([#-~ ]*)\""),
     j,'a','b','c','d','e') then
   mprint(oc[c],"  ",e)
  fi
 od;
 NULL:

end:
###end show_sections

#check justification by section
###wellformed?
wellformed?:= proc(file,path)
 local junk,j,a,b,defaults,opts,help,tags;
 defaults:=Help=no,Tags=["SECT","MARK"];
 opts:= subs([ op(select(type,[args],`=`)),defaults],[Help,Tags]);
 help:=opts[1]:
 tags := opts[2]:
 if help=yes then
  mprint(
     "wellformed?(\"worksheet\",path) checks the balance b of right and
     brackets on each line of the worksheet, and keeps a running sum s.
     b is the sum of 1 and -1 where 1 = {, and -1 = }.
    If s = 0 at the end, the worksheet is justified, and you haven't
    screwed up the worksheet. Note: Do not run mwsit on a worksheet
    containing the latextools module.
    By default the lines
    start with VERS, SECT, and MARK.
  Options:
   Help=yes gives this message");
  RETURN(NULL)
 fi;

 a := 0;
 b:=0;
 junk:=mwswrite(File=file,Path=path,Tags=tags):
 for j in junk do
  a:=CHECK_(j);
  b:=b+a;
  mprint(StringTools[SubString](j,2..5),"  ",a,"  ",b)
 od;
 if b = 0 then
  "justified"
 else  
  "no"  
 fi;

end:
###end wellformed?

>    ###mwsrootwork
mwsrootwork := proc(root,path)
 local file,line,outfile,f,index,index_mark,num,k,bkmk,tline,offset,toc,phs,
       billy,a,b,c,d,e,tfile,sline,help,opts,defaults,names,bill,i,j,pgph,files,comments,
       separator,newroot,header,index_top,level,oc,zipp,index_type,bquo,brem;
 defaults:=Help=no, Files=[],Names= [],Comments=[],Separator=" .... ",
       Newroot=yes,Toclevel=10,Zip=no,Index_type=10000;
 opts:= subs([ op(select(type,[args],`=`)),defaults],
       [Help,Files,Names,Comments,Separator,Newroot,Toclevel,Zip,Index_type]);
 help:=opts[1];
 files:=opts[2]:
 names:=opts[3];
 comments:= opts[4];
 separator:=opts[5];
 newroot:=opts[6];
 level:=opts[7]:
 zipp:= opts[8]:
 index_type:=opts[9]:

 oc["0"]:=" ":  
 oc["1"]:="+":
 offset :=  (n,b) ->  cat(" ",n," \"",oc[b],seq(" ",i=1..n-1),"\"");

 if help=yes then
  mprint("mwsrootwork(\"rootname\",\"path\",Files=[\"file1\"])
      where rootname is the name you have chosen for the root worksheet and
      [\"file1\",...] is the list (at least one) of worksheets in the document.
      A worksheet rootname.mws is created.  The section bookmarks from Files are used
      to form a table of contents; the index bookmarks are used to form an index.
      Sections which are closed are marked with a +.  Note:  If you just want to
      see a listing of sections of a file, use show_sections(\"file\",\"path\");
  Options:
   Names=[]  set to a list of names to use (Chapter 1 etc) in the root worksheet
   Comments=[]  set to a list of short (20 or so characters) descriptions of chapters
   Separator=\" .... \"  Change this if you don't like it.
   Index_type=10000  set to the number of index entries per line.
   Newroot=yes  set to no if you want to keep the current root above the Table of Contents.
   Toclevel=10   set to  3 to show the first three levels in table of contents.
   Zip=no  set to yes to zip the files into a zipfile named root.
        set to only if that is all you want to do.");  
  RETURN(NULL);
 fi;

 if nops(files)=0 then
  ERROR("Need a list of your files. See Help=yes.")
 fi;

 if zipp = only then
  currentdir(path);
  system(cat("zip ",root," ",root,".mws ",op(map(cat,files,".mws "))));
  mprint("A zipfile ",root,".zip,
     containing ",root,".mws",", ",op(map(cat,files,".mws, ")),
     "has been created in ",path,".") ;
  RETURN(NULL);
 fi;  

 if nops(names)<nops(files) then
  mprint("Filling Names with Files");
  names:= [op(names),seq(files[i],i=nops(names)+1..nops(files))];  
 fi;

 if nops(comments)<nops(files) then
  mprint("Filling Comments with Files");
  comments:= [op(comments),seq(files[i],i=nops(comments)+1..nops(files))]:  fi;
  currentdir(path);

  outfile := cat(root,".mws");

  if newroot=no then
   try
    fopen(outfile,READ,TEXT)
   catch "file already open":
    fclose(outfile);
    fopen(outfile,READ,TEXT);
   end try;

   pgph:= readline(outfile);
   line:= readline(outfile);
   if length(line)>72 then
    while line<>0 do
     pgph:= cat(pgph,line);
     line:=readline(outfile)
    od;
   else
    while line<>0 do
     if StringTools[SubString](line,71..72)="\\+" then
      line := StringTools[SubString](line,1..70)
     fi;
     pgph := cat(pgph,line);
     line := readline(outfile);
    od;
   fi;
   fclose(outfile);

   bill:=StringTools[Search](cat("{",SECT_," 0 {",PARA_,
       " 256 \"\" 0 \"\" {",TEXT_," -1 18 \" Table of Contents\" }}"),pgph):
   if bill>0 then
    header:=StringTools[SubString](pgph,1..bill-1)
   else
    ERROR("No table of contents.")
   fi;
  fi; #end newroot
  num:= 1000;
  index_mark := cat("{",PARA_," 0 \"\" [0-9]+ \"([#-~ ]+)\""):
  index_top:=cat("{",SECT_," 0 {",PARA_," 256 \"\" 0 \"\" {",TEXT_," -1 6 \" Index\" }}");
  index:= NULL:
  toc:= cat("{",SECT_," 0 {",PARA_," 256 \"\" 0 \"\" {",
    TEXT_," -1 18 \" Table of Contents\" }}");

  f := proc(a,b)
   local c,d;
   c:= StringTools[LowerCase](op(a)[1]);  
   d:= StringTools[LowerCase](op(b)[1]);
   if member(StringTools[LexOrder](c,d),{-1,0}) then
    true
   else
    false
   fi
  end;

  try
   fopen(outfile,WRITE,TEXT)
  catch "file already open":
   fclose(outfile);
   fopen(outfile,WRITE,TEXT);
  end try;

  if newroot=no then
   for i in [header] do
    writeline(outfile,i);
   od;
  else
   writeline(outfile,"{VERSION 6 0 \"IBM INTEL NT \"6.0\" }");
   writeline(outfile,"{USTYLETAB {CSTYLE \"Hyperlink\" -1 17 \"\" 0 1 0 128 128 1 0 0 1 0 0 0 0 ");
   writeline(outfile,"0 0 1 }{CSTYLE \"\" -1 256 \"\" 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 }{PSTYLE \"");
   writeline(outfile,"Normal\" -1 0 1 {CSTYLE \"\" -1 -1 \"\" 0 1 114 32 105 0 0 0 0 0 0 0 0 0 0 ");
   writeline(outfile,"1 }0 0 0 -1 -1 -1 0 0 0 0 0 0 -1 0 }{PSTYLE \"Heading 1\" 0 3 1 {CSTYLE");
   writeline(outfile,"\"\" -1 -1 \"\" 1 18 0 0 0 0 0 1 0 0 0 0 0 0 0 1 }1 0 0 0 6 6 0 0 0 0 0 0 ");
   writeline(outfile,"-1 0 }{PSTYLE \"\" 3 256 1 {CSTYLE \"\" -1 -1 \"\" 0 1 44 0 96 0 0 0 0 0 0 ");
   writeline(outfile,"0 0 0 0 1 }3 0 0 -1 -1 -1 0 0 0 0 0 0 -1 0 }}");
   writeline(outfile,cat("{",SECT_," 0"));
  fi;

  for j from 1 to nops(files)  do
   file := cat(files[j],".mws");
   try
    fopen(file,READ,TEXT)
   catch "file already open":
    fclose(file);
    fopen(file,READ,TEXT);
   end try;

   bill:=cat("{EXCHG {",PARA_," 0 \"\" 0 \"\" {HYPERLNK 17 \"",
     names[j],"\" 1 \"",file,"\"   \"\" }{TEXT -1 ",length(comments[j])+length(separator),
     " \"",separator,comments[j],"\" }}}");
   toc := toc,bill;
   pgph:= NULL:
   line:= readline(file);
   while line<>0 do
    if length(line)=72 and StringTools[SubString](line,71..72)="\\+" then
     line := StringTools[SubString](line,1..70)
    fi;
    pgph := cat(pgph,line);
    line := readline(file);
   od;

   fclose(file);

   pgph := StringTools[SubstituteAll](pgph,"{",cat(StringTools[Char](3),"{"));
   pgph:= StringTools[Split](pgph,StringTools[Char](3));

   phs := NULL:
   tline:= NULL:
   for line in pgph do
    if StringTools[RegMatch](index_mark,line,'a','b') then
     bill := map(StringTools[Trim],StringTools[Split](b,"|"));
     for i in bill do
      index := index,[i,b,file]
     od;
    fi;

    if StringTools[SubString](line,2..5)="SECT"  then
     sline:=cat(tline);
     phs := phs,sline;
     tline := line;
    else
     tline := tline,line
    fi;
   od;
   sline:=cat(tline);
   phs:= phs,sline;
   phs := [phs];
   phs := mwswrite(List=phs,Tags=["SECT","CSTY","MARK"]);
   k := 1;
   for line in phs do
    if StringTools[RegMatch](
        cat("{",SECT_," ([01]) {",PARA_," ([-0-9]+) \"\" 0 \"([#-~ ]+)\""),
        line,'a','b','c','d') then
     if k <= level then
     toc := toc,
     cat("{",EXCHG_," {",PARA_," 0 \"\" 0 \"\" {",TEXT_," -1 ",
        offset(4*k,b),"}{HYPERLNK 17 \"",d,"\" 1 \"",file,"\"   \"",d,"\" }}}");
    fi;
    k := k+CHECK_(line);  
   fi;
  od;
 od;  

 toc:= [toc]:
 for i  from 1 to nops(toc)-1 do
  writeline(outfile,toc[i])
 od;
 writeline(outfile,cat(toc[-1],"}")); #close the toc section

 if nops([index])>0 then
  writeline(outfile,index_top);
  billy := sort([index],f);
  bquo := iquo(nops(billy),index_type,'brem');
  for i from 1 to bquo do
   bill:= cat("{EXCHG {",PARA_," 0 \"\" 0 \"\" ",
      seq(cat("{HYPERLNK 17 \"",billy[(i-1)*index_type+j][1],"\" 1 \"",
      billy[(i-1)*index_type+j][3],"\" \"",billy[(i-1)*index_type+j][2],"\" }{",
      TEXT_," -1 0 \"   \" }"),j=1..index_type),"}}");
   if i = bquo and brem=0 then
    bill:= cat(bill,"}}")
   fi:
   writeline(outfile,bill);
  od;
  if brem >0 then
   bill:= cat("{EXCHG {",PARA_," 0 \"\" 0 \"\" ",
       seq(cat("{HYPERLNK 17 \"",billy[(bquo)*index_type+j][1],"\" 1 \"",
       billy[(bquo)*index_type+j][3],"\" \"",billy[(bquo)*index_type+j][2],"\" }{",
       TEXT_," -1 0 \"   \" }"),j=1..brem),"}}}}"); writeline(outfile,bill);
  fi;
 else
  writeline(outfile,cat(index_top,"}}"))
 fi;

 writeline(outfile,cat("{",MARK_," \"0 0 0\" 0 }{VIEWOPTS 1 1 0 1 1 1803 1 1 1 1 }{PAGENUMBERS 0 1 2 33 1 1 }"));
 fclose(outfile);
 mprint("The root worksheet ",outfile," is created.  
    Open it to check the Table of Contents and Index.");
 if zipp = yes then
  system(cat("zip ",root," ",outfile," ",op(map(cat,files,".mws "))));
  mprint("A zipfile ",root,".zip is in ",path,", containing ",outfile,
      " ",op(map(cat,files,".mws ")))
 fi;  

end:
###end mwsrootwork

###mwszip
mwszip := proc(root,path,files)
 mwsrootwork(root,path,Files=files,Zip=only);
end;
###end mwszip

###makexam  
makexam := proc(name,path)
 local bill,j,v,getperm,defaults,opts,help,vrsn1,n,title,date,points,
       instructions,bottom,extrapre,dvi,docstyle,key,spacing,cov,spac,i,sansf,nam,extrabrevs,identifier;
 defaults:=
 Help=no,
 Version=1,
 Title="Ma xxx yyy  Exam z",
 Date="9/22/2004",
 Points="",
 Instructions="Work each problem carefully in the space provided, giving justification
   for your answer.  If you need additional space, use the back of the preceeding page.
   Clearly indicate your answers to the questions in the problem.  \\textbf{You must
   show your work to receive any  credit for your answers.}  The use of calculators is
   permitted.",
 Bottom="\\noindent\\textbf{Name:}\\rule{2in}{.01in}",
 ExtraPreamble="",
 ExtraAbbrevs=[],
 Dvips=" -r* ",
 Docstyle="[titlepage]{article}",
 Key=yes,
 Spacing=vf,
 Cover=yes,
 Sanserif =no,
 Name=name;
 opts:= subs([ op(select(type,[args],`=`)),defaults],   
     [Help,Version,Title,Date,Points,Instructions,Bottom,ExtraPreamble,Dvips,Docstyle,
     Key,Spacing,Cover,Sanserif,Name,ExtraAbbrevs,Identifier]);
 help:=opts[1];
 if help=yes then
  mprint("
    makexam(\"worksheet\",\"path\",options)  where
    options are
    Version=\"\" #set to [[A], [1,2,3], [4,7,9]],
    where A is the version name, [1,2,3] is some permutation, and
    [4,7,9] is the list of problem nos (in increasing order) used in worksheet
    or set to a number n if you just want the first n problems in your worksheet.
    Title=\"Ma xxx yyy  Exam z\",
    Date=\"9/22/2004\",
    Points=\"\", # set to a list of points per problem otherwise 10 points per
    Instructions=\"Work each problem carefully in the space provided, giving justification
    for your answer.  If you need additional space, use the back of the preceeding page.      
    Clearly indicate your answers to the questions in the problem.  \\textbf{You must
    show your work to receive any  credit for your answers.}  The use of calculators is
    permitted.\",
  Bottom=\"\\noindent\\textbf{Name:}\\rule{2in}{.01in}\",
  ExtraPreamble=\"\",  Add stuff (such as newcommands) to the preamble. Also change pagestyle and markright etc.
  ExtraAbbrevs=[]  Put in your list of substitution pairs: [from::string,to::string]  
  Dvips=\" -r* \",
  Docstyle=\"[titlepage]{article}\",
  Key=yes,
  Spacing=\"\", set to a list, for example [2,1,np] leaves 2 inches after problem 1, 1
    inch after problem 2, and np gives a newpage after problem 3.
  Cover=yes, #set to no for no cover page or set to any latex string for the top of the quiz or exam.
  Sanserif =no  set to yes for san serif font
  Identifier=[]  Defaults to Version unless set to a string."); RETURN(NULL) fi;

  vrsn1:=opts[2];
  if member(vrsn1,{seq(i,i=1..500)}) then
   n := vrsn1;
   vrsn1:=[[A],[seq(i,i=1..n)],[seq(i,i=1..n)]]
  elif nops(vrsn1)<>3 or not type(vrsn1[1],list) or not type(vrsn1[2],list) or
  not type(vrsn1[3],list) then ERROR("Version=  needs three list arguments, see makexam(Help=\"yes\")")
  else n:=nops({op(vrsn1[2])}):
  if min(op(vrsn1[2]))<>1 or max(op(vrsn1[2]))<>n then ERROR("The second argument of Version= must be a permutation of [1,..,n]") fi;
  if n > nops({op(vrsn1[3])}) or vrsn1[3]<>sort(vrsn1[3]) then ERROR("The third argument of Version=  must be an increasing sequence the same length as the second argument") fi;
  
  fi;
  identifier:=opts[17]:
  if not type(identifier,string) then identifier:=convert(vrsn1[1][1],string) fi;
  title:=opts[3];
  date:=opts[4];
  points:=opts[5];
  if points="" then
   points := [seq(10,i=1..n)]
  fi;
  instructions:=opts[6];
  bottom:=opts[7];
  extrapre:=opts[8];
  #print(extrapre);
  if extrapre="" then   extrapre:=cat("\\raggedright\n\\topmargin=0.0in\n\\textheight=8.75in\\pagestyle{myheadings}\n\\markright{",cat(title,"",identifier),"}")
  fi;
  dvi:=opts[9];
  docstyle:=opts[10];
  key:=opts[11];
  spacing:=opts[12];
  if  spacing="" or type(spacing,list) and nops(spacing)<n then
   spacing:=[op(spacing),seq(0,i=1..n-nops(spacing))]
  fi;
if spacing="vf" then
   spacing:=[seq(0,i=1..n)]
  fi;
  spac := NULL:
  for i from 1 to nops(spacing) do
   if spacing[i]=np then
    spac:=spac,"\\newpage"
   elif spacing[i]=vf then
    spac:=spac,"\\vfill"
   elif spacing[i]=vn then
    spac:=spac,"\\vfill\\newpage"
   elif not type(spacing[i],string) then     
    spac:=spac,cat("\\vspace\{",convert(spacing[i],symbol),"in\}")
   else spac:=spac,spacing[i]
   fi;
  od;
  spacing:=[spac];
  sansf := opts[14];
  if sansf<>no then  
   extrapre:=cat("\\renewcommand{\\familydefault}{cmss}",extrapre)
  fi;
  cov:=opts[13];
  if cov=no then
   cov:=""
  fi:
  nam := opts[15]:
  extrabrevs:=opts[16];
  
  getperm := proc(l)
   local p,i,j;
   p:= NULL:
   for i from 1 to nops(l) do
    for j from 1 to nops(l) do
     if l[j]=i then
      p := p,j;
     fi;
    od
   od;
   [p]
  end:

  if cov = yes then
   bill:=cover(Title=title,
   Date=cat(date,identifier),
   Instructions=instructions,
   Posspts=points,
   Bottom=bottom)
  else
   bill := cov
  fi;
 

>     extractlatex(name,path,
   Number=n,
   Head=bill,
   PPP=spacing,Probs=vrsn1[3],
   Randomize=getperm(vrsn1[2]),
   Key=key,
   Name=cat(nam,"v",StringTools[SubstituteAll](convert(vrsn1[1][1],string)," ","")));

>     ;

>     latexit(cat(nam,"v",
StringTools[SubstituteAll](convert(vrsn1[1][1],string)," ",""),"_la"),path,
   ExtraPreamble=extrapre,
   Abbrevs=ABBREVS,
   GenAbbrevs=extrabrevs,
     Dvips=dvi,
   NumPass=1,
   Docstyle=docstyle)

end:
###end makexam

>   
end module;
with(latextools):

MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...
MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...
MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...
MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...
MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...
MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...
MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...
MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...
MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...
MCtools := module () local ver, MYMAGIC_, chkp, chkf; export MCdefaults, addlink, addimg, addsectionhint, ah_, addvlink, archiveit, ARRW, av_, Axes, brak, CARR, colors, DL, DV, fill, generator, GP, GP2...

[`&=`, `&==`, AKhint, ARRW, Autoline, Axes, CARR, DL, DV, GP, GP2, GP3, Header, Line, MCdefaults, MM, PA, PARAMS, PC, PCWSE, PP, PT, RANDANS, abc_, ac_, acew_, addimg, addlink, addpic, addsectionhint, ...
[`&=`, `&==`, AKhint, ARRW, Autoline, Axes, CARR, DL, DV, GP, GP2, GP3, Header, Line, MCdefaults, MM, PA, PARAMS, PC, PCWSE, PP, PT, RANDANS, abc_, ac_, acew_, addimg, addlink, addpic, addsectionhint, ...
[`&=`, `&==`, AKhint, ARRW, Autoline, Axes, CARR, DL, DV, GP, GP2, GP3, Header, Line, MCdefaults, MM, PA, PARAMS, PC, PCWSE, PP, PT, RANDANS, abc_, ac_, acew_, addimg, addlink, addpic, addsectionhint, ...
[`&=`, `&==`, AKhint, ARRW, Autoline, Axes, CARR, DL, DV, GP, GP2, GP3, Header, Line, MCdefaults, MM, PA, PARAMS, PC, PCWSE, PP, PT, RANDANS, abc_, ac_, acew_, addimg, addlink, addpic, addsectionhint, ...

"EXECUTE latextoolshelp(); FOR Startup Help."

latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...
latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...
latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...
latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...
latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...
latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...
latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...
latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...
latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...
latextools := module () local bigcolorlist, cc, correctcc, ABBREVS, ABBREVSAMS, AMSMACROS, DOCSTYLE, DOCSTYLEAMS, FONTS, LENGTHS, MACROS, PKGS, PKGSAMS, PSTYLE, PREAMBLE, PSTYLEAMS, SSFONTS, VERSION, c...