--- loncom/xml/lonxml.pm	2003/08/04 14:30:34	1.267
+++ loncom/xml/lonxml.pm	2003/09/21 21:40:06	1.280
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # XML Parser Module 
 #
-# $Id: lonxml.pm,v 1.267 2003/08/04 14:30:34 sakharuk Exp $
+# $Id: lonxml.pm,v 1.280 2003/09/21 21:40:06 www Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -69,6 +69,7 @@ use Safe::Hole();
 use Math::Cephes();
 use Math::Random();
 use Opcode();
+use POSIX qw(strftime);
 
 
 sub register {
@@ -104,6 +105,7 @@ use Apache::loncommon();
 use Apache::lonfeedback();
 use Apache::lonmsg();
 use Apache::loncacc();
+use Apache::lonlocal;
 
 #==================================================   Main subroutine: xmlparse  
 #debugging control, to turn on debugging modify the correct handler
@@ -174,113 +176,13 @@ sub xmlbegin {
 }
 
 sub xmlend {
-    my ($discussiononly,$symb)=@_;
-    my $discussion='';
-    if ($ENV{'request.course.id'}) {
-       my $crs='/'.$ENV{'request.course.id'};
-       if ($ENV{'request.course.sec'}) {
-          $crs.='_'.$ENV{'request.course.sec'};
-       }                 
-       $crs=~s/\_/\//g;
-       my $seeid=&Apache::lonnet::allowed('rin',$crs);
-       unless ($symb) {
-           $symb=&Apache::lonnet::symbread();
-       }
-       if ($symb) {
-          my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
-                     $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
-          if ($contrib{'version'}) {
-              unless ($discussiononly) {
-                 $discussion.=
-                  '<address><hr />';
-	     }
-              my $idx;
-              for ($idx=1;$idx<=$contrib{'version'};$idx++) {
-		my $hidden=($contrib{'hidden'}=~/\.$idx\./);
-		my $deleted=($contrib{'deleted'}=~/\.$idx\./);
-		unless ((($hidden) && (!$seeid)) || ($deleted)) {
-                 my $message=$contrib{$idx.':message'};
-                 $message=~s/\n/\<br \/\>/g;
-		 $message=&Apache::lontexconvert::msgtexconverted($message);
-                 if ($contrib{$idx.':attachmenturl'}) {
-                     my ($fname,$ft)
-                        =($contrib{$idx.':attachmenturl'}=~/\/(\w+)\.(\w+)$/);
-		     $message.='<p>Attachment: <a href="'.
-	       &Apache::lonnet::tokenwrapper($contrib{$idx.':attachmenturl'}).
-                     '"><tt>'.$fname.'.'.$ft.'</tt></a>';
-                 }
-                 if ($message) {
-                  if ($hidden) {
-		      $message='<font color="#888888">'.$message.'</font>';
-                  }
-                  my $screenname=&Apache::loncommon::screenname(
-                               $contrib{$idx.':sendername'},
-			       $contrib{$idx.':senderdomain'});
-                  my $plainname=&Apache::loncommon::nickname(
-                               $contrib{$idx.':sendername'},
-			       $contrib{$idx.':senderdomain'});
-
-                  my $sender='Anonymous';
-                  if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
-                      $sender=&Apache::loncommon::aboutmewrapper(
-                               $plainname,
-                               $contrib{$idx.':sendername'},
-                               $contrib{$idx.':senderdomain'}).' ('.
-                              $contrib{$idx.':sendername'}.' at '.
-		      $contrib{$idx.':senderdomain'}.')';
-                      if ($contrib{$idx.':anonymous'}) {
-			  $sender.=' [anonymous] '.
-                                     $screenname;
-                      }
-                      if ($seeid) {
-			  if ($hidden) {
-                             $sender.=' <a href="/adm/feedback?unhide='.
-				 $symb.':::'.$idx.'">Make Visible</a>';
-                          } else {
-                             $sender.=' <a href="/adm/feedback?hide='.
-				 $symb.':::'.$idx.'">Hide</a>';
-			  }                     
-                          $sender.=' <a href="/adm/feedback?deldisc='.
-				 $symb.':::'.$idx.'">Delete</a>';
-                      }
-                  } else {
-                      if ($screenname) {
-			  $sender='<i>'.$screenname.'</i>';
-                      }
-                  }
-		  $discussion.='<p><b>'.$sender.'</b> ('.
-                      localtime($contrib{$idx.':timestamp'}).
-                      '):<blockquote>'.$message.
-                      '</blockquote></p>';
-	        }
-               } 
-              }
-              unless ($discussiononly) {
-                 $discussion.='</address>';
-	      }
-          }
-          if ($discussiononly) {
-	      $discussion.=(<<ENDDISCUSS);
-<form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data">
-<input type="submit" name="discuss" value="Post Discussion" />
-<input type="submit" name="anondiscuss" value="Post Anonymous Discussion" />
-<input type="hidden" name="symb" value="$symb" />
-<input type="hidden" name="sendit" value="true" />
-<br />
-<font size="1">Note: in anonymous discussion, your name is visible only to
-course faculty</font><br />
-<textarea name=comment cols=60 rows=10 wrap=hard></textarea>
-<p>
-Attachment (128 KB max size): <input type="file" name="attachment" />
-</p>
-</form>
-ENDDISCUSS
-             $discussion.=&Apache::lonfeedback::generate_preview_button();
-          }
-       }
+    my $mode='xml';
+    my $status='OPEN';
+    if ($Apache::lonhomework::parsing_a_problem) {
+	$mode='problem';
+	$status=$Apache::inputtags::status[-1]; 
     }
-    return $discussion.($discussiononly?'':'</html>');
+    return &Apache::lonfeedback::list_discussion().'</html>';
 }
 
 sub tokeninputfield {
@@ -477,24 +379,25 @@ sub htmlclean {
 }
 
 sub latex_special_symbols {
-    my ($current_token,$stack,$parstack,$where)=@_;
+    my ($string,$where)=@_;
     if ($where eq 'header') {
-	$current_token =~ s/(\\|_|\^)/ /g;
-	$current_token =~ s/(\$|%|\#|&|\{|\})/\\$1/g;
+	$string =~ s/(\\|_|\^)/ /g;
+	$string =~ s/(\$|%|\#|&|\{|\})/\\$1/g;
+	$string =~ s/_/ /g;
     } else {
-	$current_token=~s/\\ /\\char92 /g;
-	$current_token=~s/\^/\\char94 /g;
-	$current_token=~s/\~/\\char126 /g;
-	$current_token=~s/(&[^A-Za-z\#])/\\$1/g;
-	$current_token=~s/([^&])\#/$1\\#/g;
-	$current_token=~s/(\$|_|{|})/\\$1/g;
-	$current_token=~s/\\char92 /\\texttt{\\char92}/g;
-	$current_token=~s/(>|<)/\$$1\$/g; #more or less
-	if ($current_token=~m/\d%/) {$current_token =~ s/(\d)%/$1\\%/g;} #percent after digit
-	if ($current_token=~m/\s%/) {$current_token =~ s/(\s)%/$1\\%/g;} #persent after space
-	if ($current_token eq '%.') {$current_token = '\%.';} #persent at the end of statement
+	$string=~s/\\ /\\char92 /g;
+	$string=~s/\^/\\char94 /g;
+	$string=~s/\~/\\char126 /g;
+	$string=~s/(&[^A-Za-z\#])/\\$1/g;
+	$string=~s/([^&])\#/$1\\#/g;
+	$string=~s/(\$|_|{|})/\\$1/g;
+	$string=~s/\\char92 /\\texttt{\\char92}/g;
+	$string=~s/(>|<)/\$$1\$/g; #more or less
+	if ($string=~m/\d%/) {$string =~ s/(\d)%/$1\\%/g;} #percent after digit
+	if ($string=~m/\s%/) {$string =~ s/(\s)%/$1\\%/g;} #percent after space
+	if ($string eq '%.') {$string = '\%.';} #percent at the end of statement
     }
-    return $current_token;
+    return $string;
 }
 
 sub inner_xmlparse {
@@ -584,14 +487,14 @@ sub inner_xmlparse {
       if (($token->[0] eq 'T') || ($token->[0] eq 'C') || ($token->[0] eq 'D') ) {
 	  #Style file definitions should be correct
 	  if ($target eq 'tex' && ($Apache::lonxml::usestyle)) {
-	      $result=&latex_special_symbols($result,$stack,$parstack);
+	      $result=&latex_special_symbols($result);
 	  }
       }
 
       # Encode any high ASCII characters
-      if (!$Apache::lonxml::prevent_entity_encode) {
-	$result=&HTML::Entities::encode($result,"\200-\377");
-      }
+#      if (!$Apache::lonxml::prevent_entity_encode) {
+#	$result=&HTML::Entities::encode($result,"\200-\377");
+#      }
       if ($Apache::lonxml::redirection) {
 	$Apache::lonxml::outputstack['-1'] .= $result;
       } else {
@@ -890,7 +793,7 @@ sub decreasedepth {
     $Apache::lonxml::olddepth=$Apache::lonxml::depth+1;
   }
   if (  $Apache::lonxml::depth < -1) {
-    &Apache::lonxml::warning("Missing tags, unable to properly run file.");
+    &Apache::lonxml::warning(&mt("Missing tags, unable to properly run file."));
     $Apache::lonxml::depth='-1';
   }
   my $curdepth=join('_',@Apache::lonxml::depthcounter);
@@ -952,83 +855,105 @@ sub store_counter {
 }
 
 sub get_all_text {
- my($tag,$pars)= @_;
- &Apache::lonxml::debug("Got a ".ref($pars));
- my $gotfullstack=1;
- if (ref($pars) ne 'ARRAY') {
-     $gotfullstack=0;
-     $pars=[$pars];
- }
- my $depth=0;
- my $token;
- my $result='';
- if ( $tag =~ m:^/: ) { 
-   my $tag=substr($tag,1); 
-   #&Apache::lonxml::debug("have:$tag:");
-   my $top_empty=0;
-   while (($depth >=0) && ($#$pars > -1) && (!$top_empty)) {
-     while (($depth >=0) && ($token = $$pars[-1]->get_token)) {
-       #&Apache::lonxml::debug("e token:$token->[0]:$depth:$token->[1]:".$#$pars.":".$#Apache::lonxml::pwd);
-       if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
-	 $result.=$token->[1];
-       } elsif ($token->[0] eq 'PI') {
-	 $result.=$token->[2];
-       } elsif ($token->[0] eq 'S') {
-	 if ($token->[1] =~ /^$tag$/i) { $depth++; }
-	 $result.=$token->[4];
-       } elsif ($token->[0] eq 'E')  {
-	 if ( $token->[1] =~ /^$tag$/i) { $depth--; }
-	 #skip sending back the last end tag
-	 if ($depth > -1) { $result.=$token->[2]; } else {
-	   $$pars[-1]->unget_token($token);
-	 }
-       }
-     }
-     if (($depth >=0) && ($#$pars == 0) ) { $top_empty=1; }
-     if (($depth >=0) && ($#$pars > 0) ) {
-       pop(@$pars);
-       pop(@Apache::lonxml::pwd);
-     }
-   }
-   if ($top_empty && $depth >= 0) {
-       #never found the end tag ran out of text, throw error send back blank
-       &error('Never found end tag for &lt;'.$tag.'&gt;');
-       if ($gotfullstack) {
-	   my $newstring='</'.$tag.'>'.$result;
-	   &Apache::lonxml::newparser($pars,\$newstring);
-       }
-       $result='';
-   }
- } else {
-     while ($#$pars > -1) {
-	 while ($token = $$pars[-1]->get_token) {
-	     #&Apache::lonxml::debug("s token:$token->[0]:$depth:$token->[1]");
-	     if (($token->[0] eq 'T')||($token->[0] eq 'C')||
-		 ($token->[0] eq 'D')) {
-		 $result.=$token->[1];
-	     } elsif ($token->[0] eq 'PI') {
-		 $result.=$token->[2];
-	     } elsif ($token->[0] eq 'S') {
-		 if ( $token->[1] =~ /^$tag$/i) {
-		     $$pars[-1]->unget_token($token); last;
-		 } else {
-		     $result.=$token->[4];
-		 }
-	     } elsif ($token->[0] eq 'E')  {
-		 $result.=$token->[2];
-	     }
-	 }
-	 if (($#$pars > 0) ) {
-	     pop(@$pars);
-	     pop(@Apache::lonxml::pwd);
-	 } else { last; }
-     }
- }
- if ($result =~ m|<LONCAPA_INTERNAL_TURN_STYLE_ON />|) {
-     $Apache::lonxml::usestyle=1;
- }
- #&Apache::lonxml::debug("Exit:$result:");
- return $result
+    my($tag,$pars,$style)= @_;
+    &Apache::lonxml::debug("Got a ".ref($pars));
+    my $gotfullstack=1;
+    if (ref($pars) ne 'ARRAY') {
+	$gotfullstack=0;
+	$pars=[$pars];
+    }
+    &Apache::lonxml::debug("Got a ".ref($style));
+    if (ref($style) ne 'HASH') {
+	$style={};
+    } else {
+	&Apache::lonhomework::showhash(%$style);
+    }
+    my $depth=0;
+    my $token;
+    my $result='';
+    if ( $tag =~ m:^/: ) { 
+	my $tag=substr($tag,1); 
+	#&Apache::lonxml::debug("have:$tag:");
+	my $top_empty=0;
+	while (($depth >=0) && ($#$pars > -1) && (!$top_empty)) {
+	    while (($depth >=0) && ($token = $$pars[-1]->get_token)) {
+		#&Apache::lonxml::debug("e token:$token->[0]:$depth:$token->[1]:".$#$pars.":".$#Apache::lonxml::pwd);
+		if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
+		    $result.=$token->[1];
+		} elsif ($token->[0] eq 'PI') {
+		    $result.=$token->[2];
+		} elsif ($token->[0] eq 'S') {
+		    if ($token->[1] =~ /^$tag$/i) { $depth++; }
+		    if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/i) { $Apache::lonxml::usestyle=1; }
+		    if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/i) { $Apache::lonxml::usestyle=0; }
+		    $result.=$token->[4];
+		} elsif ($token->[0] eq 'E')  {
+		    if ( $token->[1] =~ /^$tag$/i) { $depth--; }
+		    #skip sending back the last end tag
+		    if ($depth == 0 && exists($$style{'/'.$token->[1]})) {
+			my $string=
+			    '<LONCAPA_INTERNAL_TURN_STYLE_OFF end="yes" />'.
+				$$style{'/'.$token->[1]}.
+				    $token->[2].
+					'<LONCAPA_INTERNAL_TURN_STYLE_ON />';
+			&Apache::lonxml::newparser($pars,\$string);
+			#&Apache::lonxml::debug("reParsing $string");
+			next;
+		    }
+		    if ($depth > -1) {
+			$result.=$token->[2];
+		    } else {
+			$$pars[-1]->unget_token($token);
+		    }
+		}
+	    }
+	    if (($depth >=0) && ($#$pars == 0) ) { $top_empty=1; }
+	    if (($depth >=0) && ($#$pars > 0) ) {
+		pop(@$pars);
+		pop(@Apache::lonxml::pwd);
+	    }
+	}
+	if ($top_empty && $depth >= 0) {
+	    #never found the end tag ran out of text, throw error send back blank
+	    &error('Never found end tag for &lt;'.$tag.
+		   '&gt; current string <pre>'.
+		   &HTML::Entities::encode($result).
+		   '</pre>');
+	    if ($gotfullstack) {
+		my $newstring='</'.$tag.'>'.$result;
+		&Apache::lonxml::newparser($pars,\$newstring);
+	    }
+	    $result='';
+	}
+    } else {
+	while ($#$pars > -1) {
+	    while ($token = $$pars[-1]->get_token) {
+		#&Apache::lonxml::debug("s token:$token->[0]:$depth:$token->[1]");
+		if (($token->[0] eq 'T')||($token->[0] eq 'C')||
+		    ($token->[0] eq 'D')) {
+		    $result.=$token->[1];
+		} elsif ($token->[0] eq 'PI') {
+		    $result.=$token->[2];
+		} elsif ($token->[0] eq 'S') {
+		    if ( $token->[1] =~ /^$tag$/i) {
+			$$pars[-1]->unget_token($token); last;
+		    } else {
+			$result.=$token->[4];
+		    }
+		    if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/i) { $Apache::lonxml::usestyle=1; }
+		    if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/i) { $Apache::lonxml::usestyle=0; }
+		} elsif ($token->[0] eq 'E')  {
+		    $result.=$token->[2];
+		}
+	    }
+	    if (($#$pars > 0) ) {
+		pop(@$pars);
+		pop(@Apache::lonxml::pwd);
+	    } else { last; }
+	}
+    }
+    #&Apache::lonxml::debug("Exit:$result:");
+    return $result
 }
 
 sub newparser {
@@ -1115,8 +1040,10 @@ sub storefile {
     if (my $fh=Apache::File->new('>'.$file)) {
 	print $fh $contents;
         $fh->close();
+        return 1;
     } else {
-      &warning("Unable to save file $file");
+	&warning("Unable to save file $file");
+	return 0;
     }
 }
 
@@ -1138,25 +1065,47 @@ SIMPLECONTENT
   return $filecontents;
 }
 
+sub createnewsty {
+  my $filecontents=(<<SIMPLECONTENT);
+<definetag name="">
+    <render>
+       <web></web>
+       <tex></tex>
+    </render>
+</definetag>
+SIMPLECONTENT
+  return $filecontents;
+}
+
 
 sub inserteditinfo {
-      my ($result,$filecontents)=@_;
+      my ($result,$filecontents,$filetype)=@_;
       $filecontents = &HTML::Entities::encode($filecontents);
 #      my $editheader='<a href="#editsection">Edit below</a><hr />';
-      my $xml_help = Apache::loncommon::helpLatexCheatsheet();
+      my $xml_help = '';
+      if ($filetype eq 'html') {
+	  $xml_help=Apache::loncommon::helpLatexCheatsheet();
+      }
+      my $cleanbut = '';
+      if ($filetype eq 'html') {
+	  $cleanbut='<input type="submit" name="attemptclean" value="'.
+	      &mt('Save and then attempt to clean HTML').'" />';
+      }
       my $titledisplay=&display_title();
+      my %lt=&Apache::lonlocal::texthash('st' => 'Save this',
+					 'vi' => 'View',
+					 'ed' => 'Edit');
       my $buttons=(<<BUTTONS);
-<input type="submit" name="attemptclean" 
-       value="Save and then attempt to clean HTML" />
-<input type="submit" name="savethisfile" value="Save this" />
-<input type="submit" name="viewmode" value="View" />
+$cleanbut
+<input type="submit" name="savethisfile" value="$lt{'st'}" />
+<input type="submit" name="viewmode" value="$lt{'vi'}" />
 BUTTONS
       my $editfooter=(<<ENDFOOTER);
 <hr />
 <a name="editsection" />
 <form method="post">
 $xml_help
-<input type="hidden" name="editmode" value="Edit" />
+<input type="hidden" name="editmode" value="$lt{'ed'}" />
 $buttons<br />
 <textarea cols="80" rows="40" name="filecont">$filecontents</textarea>
 <br />$buttons
@@ -1204,9 +1153,9 @@ sub handler {
     $Apache::lonxml::debug=$ENV{'user.debug'};
     
     if ($ENV{'browser.mathml'}) {
-	$request->content_type('text/xml');
+	&Apache::loncommon::content_type($request,'text/xml');
     } else {
-	$request->content_type('text/html');
+	&Apache::loncommon::content_type($request,'text/html');
     }
     &Apache::loncommon::no_cache($request);
     $request->send_http_header;
@@ -1215,12 +1164,20 @@ sub handler {
 
 
     my $file=&Apache::lonnet::filelocation("",$request->uri);
+    my $filetype;
+    if ($file =~ /\.sty$/) {
+	$filetype='sty';
+    } else {
+	$filetype='html';
+    }
 #
 # Edit action? Save file.
 #
     unless ($ENV{'request.state'} eq 'published') {
 	if (($ENV{'form.savethisfile'}) || ($ENV{'form.attemptclean'})) {
-	    &storefile($file,$ENV{'form.filecont'});
+	    if (&storefile($file,$ENV{'form.filecont'})) {
+		$request->print("<font COLOR=\"#0000FF\">Updated: ". strftime("%d %b %H:%M:%S",localtime())." </font>");
+	    } 
 	}
     }
     my %mystyle;
@@ -1239,7 +1196,11 @@ sub handler {
 ENDNOTFOUND
     $filecontents='';
 	if ($ENV{'request.state'} ne 'published') {
-	    $filecontents=&createnewhtml();
+	    if ($filetype eq 'sty') {
+		$filecontents=&createnewsty();
+	    } else {
+		$filecontents=&createnewhtml();
+	    }
 	    $ENV{'form.editmode'}='Edit'; #force edit mode
 	}
     } else {
@@ -1267,11 +1228,11 @@ ENDNOTFOUND
 	    $displayfile=~s/^\/[^\/]*//;
 	    $result='<html><body bgcolor="#FFFFFF"><h3>'.$displayfile.
 		'</h3></body></html>';
-	    $result=&inserteditinfo($result,$filecontents);
+	    $result=&inserteditinfo($result,$filecontents,$filetype);
 	}
     }
-    
-    writeallows($request->uri);
+    if ($filetype eq 'html') { writeallows($request->uri); }
+	
     
 
     $request->print($result);
@@ -1393,7 +1354,7 @@ sub register_insert {
     my $line = $data[$i];
     if ( $line =~ /^\#/ || $line =~ /^\s*\n/) { next; }
     if ( $line =~ /TABLE/ ) { last; }
-    my ($tag,$descrip,$color,$function,$show) = split(/,/, $line);
+    my ($tag,$descrip,$color,$function,$show,$helpfile,$helpdesc) = split(/,/, $line);
     if ($tag) {
       $insertlist{"$tagnum.tag"} = $tag;
       $insertlist{"$tagnum.description"} = $descrip;
@@ -1401,6 +1362,8 @@ sub register_insert {
       $insertlist{"$tagnum.function"} = $function;
       if (!defined($show)) { $show='yes'; }
       $insertlist{"$tagnum.show"}= $show;
+      $insertlist{"$tagnum.helpfile"} = $helpfile;
+      $insertlist{"$tagnum.helpdesc"} = $helpdesc;
       $insertlist{"$tag.num"}=$tagnum;
       $tagnum++;
     }
@@ -1435,6 +1398,20 @@ sub description {
   return $insertlist{$tagnum.'.description'};
 }
 
+# Returns a list containing the help file, and the description
+sub helpinfo {
+  my ($token)=@_;
+  my $tagnum;
+  my $tag=$token->[1];
+  foreach my $namespace (reverse @Apache::lonxml::namespace) {
+    my $testtag=$namespace.'::'.$tag;
+    $tagnum=$insertlist{"$testtag.num"};
+    if (defined($tagnum)) { last; }
+  }
+  if (!defined ($tagnum)) { $tagnum=$Apache::lonxml::insertlist{"$tag.num"}; }
+  return ($insertlist{$tagnum.'.helpfile'}, $insertlist{$tagnum.'.helpdesc'});
+}
+
 # ----------------------------------------------------------------- whichuser
 # returns a list of $symb, $courseid, $domain, $name that is correct for
 # calls to lonnet functions for this setup.
@@ -1444,7 +1421,7 @@ sub whichuser {
   my ($symb,$courseid,$domain,$name,$publicuser);
   if (defined($ENV{'form.grade_symb'})) {
     my $tmp_courseid=$ENV{'form.grade_courseid'};
-    my $allowed=&Apache::lonnet::allowed('mgr',$tmp_courseid);
+    my $allowed=&Apache::lonnet::allowed('vgr',$tmp_courseid);
     if ($allowed) {
       $symb=$ENV{'form.grade_symb'};
       $courseid=$ENV{'form.grade_courseid'};