--- loncom/homework/lonhomework.pm	2003/09/11 20:03:28	1.140
+++ loncom/homework/lonhomework.pm	2025/01/05 21:53:42	1.392
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Homework handler
 #
-# $Id: lonhomework.pm,v 1.140 2003/09/11 20:03:28 albertel Exp $
+# $Id: lonhomework.pm,v 1.392 2025/01/05 21:53:42 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -24,17 +24,13 @@
 # /home/httpd/html/adm/gpl.txt
 #
 # http://www.lon-capa.org/
-#
-# Guy Albertelli
-# 11/30 Gerd Kortemeyer
-# 6/1,8/17,8/18 Gerd Kortemeyer
-# 7/18 Jeremy Bowers
+
 
 package Apache::lonhomework;
 use strict;
 use Apache::style();
 use Apache::lonxml();
-use Apache::lonnet();
+use Apache::lonnet;
 use Apache::lonplot();
 use Apache::inputtags();
 use Apache::structuretags();
@@ -51,215 +47,727 @@ use Apache::externalresponse();
 use Apache::rankresponse();
 use Apache::matchresponse();
 use Apache::chemresponse();
+use Apache::functionplotresponse();
+use Apache::drawimage();
+use Apache::loncapamath();
+use Apache::loncourseuser();
+use Apache::grades();
 use Apache::Constants qw(:common);
-use HTML::Entities();
 use Apache::loncommon();
-#use Time::HiRes qw( gettimeofday tv_interval );
+use Apache::lonparmset();
+use Apache::lonnavmaps();
+use Apache::lonlocal;
+use LONCAPA qw(:DEFAULT :match);
+use LONCAPA::ltiutils();
+use Time::HiRes qw( gettimeofday tv_interval );
+use HTML::Entities();
+use File::Copy();
+
+# FIXME - improve commenting
+
+my $registered_cleanup;
 
 BEGIN {
-  &Apache::lonxml::register_insert();
+    &Apache::lonxml::register_insert();
+}
+
+
+=pod
+
+=item set_bubble_lines()
+
+Called at analysis time to set the bubble lines
+hash for the problem.. This should be called in the
+end_problemtype tag in analysis mode.
+
+We fetch the hash of part id counters from lonxml
+    and push them into analyze:{part_id.bubble_lines}.
+
+=cut
+
+sub set_bubble_lines {
+    my %bubble_counters = &Apache::lonxml::get_bubble_line_hash();
+
+    foreach my $key (keys(%bubble_counters)) {
+	$Apache::lonhomework::analyze{"$key.bubble_lines"} =
+	    $bubble_counters{"$key"};
+    }
 }
 
+#
+# Decides what targets to render for.
+# Implicit inputs:
+#   Various session environment variables:
+#      request.state -  published  - is a /res/ resource
+#                       uploaded   - is a /uploaded/ resource
+#                       contruct   - is a /priv/ resource
+#      form.grade_target - a form parameter requesting a specific target
 sub get_target {
-  if (($ENV{'request.state'} eq "published") ||
-      ($ENV{'request.state'} eq "uploaded")) {
-    if ( defined($ENV{'form.grade_target'}  ) 
-	 && ($ENV{'form.grade_target'} eq 'tex')) {
-      return ($ENV{'form.grade_target'});
-    } elsif ( defined($ENV{'form.grade_target'}  ) 
-	 && ($Apache::lonhomework::viewgrades eq 'F' )) {
-      return ($ENV{'form.grade_target'});
-    } elsif (defined($ENV{'form.grade_target'}  ) 
-	 && ($ENV{'form.grade_target'} eq 'answer')) {
-      return ($ENV{'form.grade_target'});
-    }
- 
-    if ( defined($ENV{'form.submitted'}) &&
-	 ( !defined($ENV{'form.resetdata'})) &&
-	 ( !defined($ENV{'form.newrandomization'}))) {
-      return ('grade', 'web');
+    &Apache::lonxml::debug("request.state = $env{'request.state'}");
+    if( defined($env{'form.grade_target'})) {
+	&Apache::lonxml::debug("form.grade_target= $env{'form.grade_target'}");
     } else {
-      return ('web');
+	&Apache::lonxml::debug("form.grade_target <undefined>");
     }
-  } elsif ($ENV{'request.state'} eq "construct") {
-    if ( defined($ENV{'form.grade_target'}) ) {
-      return ($ENV{'form.grade_target'});
-    }
-    if ( defined($ENV{'form.preview'})) {
-      if ( defined($ENV{'form.submitted'})) {
-	return ('grade', 'web');
-      } else {
-	return ('web');
-      }
-    } else {
-      if ( $ENV{'form.problemmode'} eq 'View' ||
-	   $ENV{'form.problemmode'} eq 'Discard Edits and View') {
-	if ( defined($ENV{'form.submitted'}) &&
-	     (!defined($ENV{'form.resetdata'})) &&
-	     (!defined($ENV{'form.newrandomization'}))) {
-	  return ('grade', 'web','answer');
-	} else {
-	  return ('web','answer');
-	}
-      } elsif ( $ENV{'form.problemmode'} eq 'Edit' ) {
-	if ( $ENV{'form.submitted'} eq 'edit' ) {
-	  if ( $ENV{'form.submit'} eq 'Submit Changes and View' ) {
-	    return ('modified','web','answer');
-	  } else {
-	    return ('modified','edit');
-	  }
-	} else {
-	  return ('edit');
-	}
-      } else {
-	return ('web');
-      }
+    if (($env{'request.state'} eq "published") ||
+	($env{'request.state'} eq "uploaded")) {
+	if ( defined($env{'form.grade_target'}  ) 
+	     && ($env{'form.grade_target'} eq 'tex')) {
+	    return ($env{'form.grade_target'});
+	} elsif ( defined($env{'form.grade_target'}  ) 
+		  && ($Apache::lonhomework::viewgrades eq 'F' )) {
+	    return ($env{'form.grade_target'});
+	} elsif ( $env{'form.grade_target'} eq 'webgrade'
+		  && ($Apache::lonhomework::queuegrade eq 'F' )) {
+	    return ($env{'form.grade_target'});
+	} elsif ($env{'form.grade_target'} eq 'answer') {
+            if ($env{'form.answer_output_mode'} eq 'tex') {
+                return ($env{'form.grade_target'});
+            }
+        }
+	if ($env{'form.webgrade'} &&
+	    ($Apache::lonhomework::modifygrades eq 'F'
+	     || $Apache::lonhomework::queuegrade eq 'F' )) {
+	    return ('grade','webgrade');
+	}
+	if ( defined($env{'form.submitted'}) &&
+	     ( !defined($env{'form.newrandomization'}))) {
+	    return ('grade', 'web');
+	} else {
+	    return ('web');
+	}
+    } elsif ($env{'request.state'} eq "construct") {
+#
+# We are in construction space, editing and testing problems
+#
+	if ( defined($env{'form.grade_target'}) ) {
+	    return ($env{'form.grade_target'});
+	}
+	if ( defined($env{'form.preview'})) {
+	    if ( defined($env{'form.submitted'})) {
+#
+# We are doing a problem preview
+#
+		return ('grade', 'web');
+	    } else {
+		return ('web');
+	    }
+	} else {
+	    if ($env{'form.problemstate'} eq 'WEB_GRADE') {
+		return ('grade','webgrade','answer');
+            } elsif ($env{'form.problemmode'} eq 'view') {
+                return ('grade','web','answer');
+	    } elsif ($env{'form.problemmode'} eq 'saveview') {
+                return ('modified','web','answer');
+            } elsif ($env{'form.problemmode'} eq 'discard') {
+                return ('web','answer');
+            } elsif (($env{'form.problemmode'} eq 'saveedit') ||
+                     ($env{'form.problemmode'} eq 'undo')) {
+                my %editors = &Apache::loncommon::permitted_editors();
+                if ($editors{'edit'}) {
+                    return ('modified','no_output_web','edit');
+                } else {
+                    return ('web');
+                }
+            } elsif ($env{'form.problemmode'} eq 'edit') {
+                my %editors = &Apache::loncommon::permitted_editors();
+                if ($editors{'edit'}) {
+		    return ('no_output_web','edit');
+                } else {
+                    return ('web');
+                }
+	    } else {
+		return ('web');
+	    }
+        }
+#
+# End of Authoring Space
+#
     }
-  }
-  return ();
+#
+# Huh? We are nowhere, so do nothing.
+#
+    return ();
 }
 
 sub setup_vars {
-  my ($target) = @_;
-  return ';'
+    my ($target) = @_;
+    return ';'
 #  return ';$external::target='.$target.';';
 }
 
-sub send_header {
-  my ($request)= @_;
-  $request->print(&Apache::lontexconvert::header());
-#  $request->print('<form name='.$ENV{'form.request.prefix'}.'lonhomework method="POST" action="'.$request->uri.'">');
+sub proctor_checked_in {
+    my ($slot_name,$slot,$type)=@_;
+    my @possible_proctors=split(",",$slot->{'proctor'});
+    
+    return 1 if (!@possible_proctors);
+
+    my $key;
+    if ($type eq 'Task') {
+	my $version=$Apache::lonhomework::history{'resource.0.version'};
+	$key ="resource.$version.0.checkedin";
+    } elsif (($type eq 'problem') || ($type eq 'tool')) {
+	$key ='resource.0.checkedin';
+    }
+    # backward compatability, used to be username@domain, 
+    # now is username:domain
+    my $who = $Apache::lonhomework::history{$key};
+    if ($who !~ /:/) {
+	$who =~ tr/@/:/;
+    }     
+    foreach my $possible (@possible_proctors) { 
+	if ($who eq $possible
+	    && $Apache::lonhomework::history{$key.'.slot'} eq $slot_name) {
+	    return 1;
+	}
+    }
+    return 0;
 }
 
-sub createmenu {
-  my ($which,$request)=@_;
-  if ($which eq 'grade') {
-    $request->print('<script language="JavaScript"> 
-          hwkmenu=window.open("/res/adm/pages/homeworkmenu.html","homeworkremote",
-                 "height=350,width=150,menubar=no");
-          </script>');
-  }
-}
+sub check_slot_access {
+    my ($id,$type,$symb,$partlist)=@_;
 
-sub send_footer {
-  my ($request)= @_;
-#  $request->print('</form>');
-  $request->print(&Apache::lontexconvert::footer());
-}
+    # does it pass normal muster
+    my ($status,$datemsg)=&check_access($id,$symb);
+
+    my $useslots = &Apache::lonnet::EXT("resource.0.useslots",$symb);
+    if ($useslots ne 'resource' && $useslots ne 'map' 
+	&& $useslots ne 'map_map') {
+	return ($status,$datemsg);
+    }
+
+    my $checkin = 'resource.0.checkedin';
+    my $version;
+    if ($type eq 'Task') {
+        $version=$Apache::lonhomework::history{'resource.version'};
+        $checkin = "resource.$version.0.checkedin";
+    }
+    my $checkedin = $Apache::lonhomework::history{$checkin};
+    my ($returned_slot,$slot_name,$checkinslot,$ipused,$blockip,$now,$ip,
+        $consumed_uniq);
+    $now = time;
+    $ip=$ENV{'REMOTE_ADDR'} || $env{'request.host'};
+
+    if ($checkedin) {
+        $checkinslot = $Apache::lonhomework::history{"$checkin.slot"};
+        my %slot=&Apache::lonnet::get_slot($checkinslot);
+        $consumed_uniq = $slot{'uniqueperiod'};
+        if ($slot{'iptied'}) {
+            $ipused = $Apache::lonhomework::history{"$checkin.ip"};
+            unless (($ip ne '') && 
+                    (($ipused eq $ip) || ($ENV{'REMOTE_ADDR'} eq '127.0.0.1'))) {
+                $blockip = $slot{'iptied'};
+                $slot_name = $checkinslot;
+                $returned_slot = \%slot;
+            }
+        }
+    }
+
+    if ($status eq 'SHOW_ANSWER') {
+        if ($blockip eq 'answer') {
+            return ('NEED_DIFFERENT_IP','',$slot_name,$returned_slot,$ipused);
+        } else {
+            return ($status,$datemsg);
+        }
+    }
 
-$Apache::lonxml::browse='';
+    if ($status eq 'CLOSED' ||
+	$status eq 'INVALID_ACCESS' ||
+	$status eq 'UNAVAILABLE') {
+	return ($status,$datemsg);
+    }
+    if ($env{'request.state'} eq "construct") {
+	return ($status,$datemsg);
+    }
+
+    if ($type eq 'Task') {
+	if ($checkedin &&
+	    $Apache::lonhomework::history{"resource.$version.0.status"} eq 'pass') {
+	    if ($blockip eq 'answer') {
+                return ('NEED_DIFFERENT_IP','',$slot_name,$returned_slot,$ipused);
+            } else {
+	        return ('SHOW_ANSWER');
+            }
+        }
+    } elsif (($type eq 'problem') &&
+             ($Apache::lonhomework::browse eq 'F') &&
+             ($ENV{'REMOTE_ADDR'} eq '127.0.0.1') &&
+             ($env{'form.grade_courseid'} eq $env{'request.course.id'}) &&
+             (&Apache::lonnet::allowed('mgr',$env{'request.course.id'}))) {
+        return ($status,$datemsg);
+    }
+
+    my $availablestudent = &Apache::lonnet::EXT("resource.0.availablestudent",$symb);
+    my $available = &Apache::lonnet::EXT("resource.0.available",$symb);
+    my @slots= (split(':',$availablestudent),split(':',$available));
+
+#    if (!@slots) {
+#	return ($status,$datemsg);
+#    }
+    undef($returned_slot);
+    undef($slot_name);
+    my $slotstatus='NOT_IN_A_SLOT';
+    my $num_usable_slots = 0;
+    if (!$symb) {
+        ($symb) = &Apache::lonnet::whichuser();
+    }
+    foreach my $slot (@slots) {
+	$slot =~ s/(^\s*|\s*$)//g;
+	&Apache::lonxml::debug("getting $slot");
+	my %slot=&Apache::lonnet::get_slot($slot);
+	&Apache::lonhomework::showhash(%slot);
+        next if ($slot{'endtime'} < $now);
+        $num_usable_slots ++;
+	if ($slot{'starttime'} < $now &&
+	    $slot{'endtime'} > $now &&
+	    &Apache::loncommon::check_ip_acc($slot{'ip'})) {
+            if ($slot{'iptied'}) {
+                if ($env{'request.course.id'}) {
+                    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+                    my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+                    if ($slot eq $checkinslot) {
+                        if ($ip eq $ipused) {
+                            &Apache::lonxml::debug("$slot is good");
+                            $slotstatus ='NEEDS_CHECKIN'; 
+                        } else {
+                            $slotstatus = 'NEED_DIFFERENT_IP';
+                            $slot_name = $slot;
+                            $returned_slot = \%slot;
+                            last;
+                        }
+                    } elsif ($ip) {
+                        my $uniqkey = "$slot\0$symb\0$ip";
+                        my %used_ip = &Apache::lonnet::get('slot_uniqueips',[$uniqkey],$cdom,$cnum);
+                        if ($used_ip{$uniqkey}) {
+                            $slotstatus = 'NEED_DIFFERENT_IP';
+                        } else {
+                            &Apache::lonxml::debug("$slot is good");
+                            $slotstatus ='NEEDS_CHECKIN';
+                        }
+                    }
+                }
+            } else {
+	        &Apache::lonxml::debug("$slot is good");
+	        $slotstatus='NEEDS_CHECKIN';
+            }
+            if ($slotstatus eq 'NEEDS_CHECKIN') {
+	        $returned_slot=\%slot;
+	        $slot_name=$slot;
+	        last;
+            }
+        }
+    }
+    if ($slotstatus eq 'NEEDS_CHECKIN' &&
+	&proctor_checked_in($slot_name,$returned_slot,$type)) {
+	&Apache::lonxml::debug("proctor checked in");
+	$slotstatus=$status;
+    }
+
+    my ($is_correct,$got_grade);
+    if ($type eq 'Task') {
+	my $version=$Apache::lonhomework::history{'resource.0.version'};
+	$got_grade = 
+	    ($Apache::lonhomework::history{"resource.$version.0.status"} 
+	     =~ /^(?:pass|fail)$/);
+	$is_correct =  
+	    ($Apache::lonhomework::history{"resource.$version.0.status"} eq 'pass'
+	     || $Apache::lonhomework::history{"resource.0.solved"} =~ /^correct_/ );
+    } elsif (($type eq 'problem') || ($type eq 'tool')) {
+        if ((ref($partlist) eq 'ARRAY') && (@{$partlist} > 0)) {
+            my ($numcorrect,$numgraded) = (0,0);
+            foreach my $part (@{$partlist}) {
+                my $currtries = $Apache::lonhomework::history{"resource.$part.tries"};
+                my $maxtries = &Apache::lonnet::EXT("resource.$part.maxtries",$symb);
+                my $probstatus = &Apache::structuretags::get_problem_status($part);
+                my $earlyout;
+                unless (($probstatus eq 'no') ||
+                        ($probstatus eq 'no_feedback_ever')) {
+                    if ($Apache::lonhomework::history{"resource.$part.solved"} =~/^correct_/) {
+                        $numcorrect ++;
+                    } else {
+                        $earlyout = 1;
+                    }
+                }
+                if ($currtries == $maxtries) {
+                    $earlyout = 1;
+                } else {
+                    $numgraded ++;
+                }
+                last if ($earlyout);
+            }
+            my $numparts = scalar(@{$partlist});
+            if ($numparts == $numcorrect) {
+                $is_correct = 1;
+            }
+            if ($numparts == $numgraded) {
+                $got_grade = 1;
+            }
+        } else {
+            my $currtries = $Apache::lonhomework::history{"resource.0.tries"};
+            my $maxtries = &Apache::lonnet::EXT("resource.0.maxtries",$symb);
+            my $probstatus = &Apache::structuretags::get_problem_status('0');
+            unless (($probstatus eq 'no') ||
+                    ($probstatus eq 'no_feedback_ever')) {
+                $is_correct =
+                    ($Apache::lonhomework::history{"resource.0.solved"} =~/^correct_/);
+            }
+            unless (($currtries == $maxtries) || ($is_correct)) {
+                $got_grade = 1;
+            }
+        }
+    }
+    
+    &Apache::lonxml::debug(" slot is $slotstatus checkedin ($checkedin) got_grade ($got_grade) is_correct ($is_correct)");
+    
+    # no slot is currently open, and has been checked in for this version
+    # but hasn't got a grade, therefore must be awaiting a grade
+    if (!defined($slot_name)
+	&& $checkedin 
+	&& !$got_grade) {
+	return ('WAITING_FOR_GRADE');
+    }
+
+    # Previously used slot is no longer open, and has been checked in for this version.
+    # However, the problem is not closed, and potentially, another slot might be
+    # used to gain access to it to work on it, until the due date is reached, and the
+    # problem then becomes CLOSED.  Therefore return the slotstatus - 
+    # (which will be one of: NOT_IN_A_SLOT, RESERVABLE, RESERVABLE_LATER, or NOTRESERVABLE).
+
+    if (!defined($slot_name) && (($type eq 'problem') || ($type eq 'tool'))) {
+        if ($slotstatus eq 'NOT_IN_A_SLOT') {
+            if (!$num_usable_slots) {
+                ($slotstatus,$datemsg) = &check_reservable_slot($slotstatus,$symb,$now,$checkedin,
+                                                                $consumed_uniq);
+            }
+        }
+        return ($slotstatus,$datemsg);
+    }
+
+    if ($slotstatus eq 'NOT_IN_A_SLOT' 
+	&& $checkedin ) {
+
+	if ($got_grade) {
+            if ($blockip eq 'answer') {
+                return ('NEED_DIFFERENT_IP','',$slot_name,$returned_slot,$ipused);
+            } else {
+	        return ('SHOW_ANSWER');
+            }
+	} else {
+	    return ('WAITING_FOR_GRADE');
+	}
+
+    }
+
+    if (($is_correct) && ($blockip ne 'answer')) {
+	if (($type eq 'problem') || ($type eq 'tool')) {
+	    return ($status);
+	}
+	return ('SHOW_ANSWER');
+    }
+
+    if ( $status eq 'CANNOT_ANSWER' && 
+	 ($slotstatus ne 'NEEDS_CHECKIN' && $slotstatus ne 'NOT_IN_A_SLOT' &&
+          $slotstatus ne 'NEED_DIFFERENT_IP') ) {
+	return ($status,$datemsg);
+    }
+    return ($slotstatus,$datemsg,$slot_name,$returned_slot,$ipused);
+}
+
+sub check_reservable_slot {
+    my ($slotstatus,$symb,$now,$checkedin,$consumed_uniq) = @_;
+    my $datemsg;
+    if ($slotstatus eq 'NOT_IN_A_SLOT') {
+        if ($env{'request.course.id'}) {
+            my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+            my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+            unless ($symb) {
+                ($symb)=&Apache::lonnet::whichuser();
+            }
+            $slotstatus = 'NOTRESERVABLE';
+            my ($reservable_now_order,$reservable_now,$reservable_future_order,
+                $reservable_future) =
+                &Apache::loncommon::get_future_slots($cnum,$cdom,$now,$symb);
+            if ((ref($reservable_now_order) eq 'ARRAY') && (ref($reservable_now) eq 'HASH')) {
+                if (@{$reservable_now_order} > 0) {
+                    if ((!$checkedin) || (ref($consumed_uniq) ne 'ARRAY')) {
+                        $slotstatus = 'RESERVABLE';
+                        $datemsg = $reservable_now->{$reservable_now_order->[-1]}{'endreserve'};
+                    } else {
+                        my ($uniqstart,$uniqend,$useslot);
+                        if (ref($consumed_uniq) eq 'ARRAY') {
+                            ($uniqstart,$uniqend)=@{$consumed_uniq};
+                        }
+                        foreach my $slot (reverse(@{$reservable_now_order})) {
+                            if ($reservable_now->{$slot}{'uniqueperiod'} =~ /^(\d+)\,(\d+)$/) {
+                                my ($new_uniq_start,$new_uniq_end) = ($1,$2);
+                                next if (!
+                                    ($uniqstart < $new_uniq_start && $uniqend < $new_uniq_start) ||
+                                    ($uniqstart > $new_uniq_end   &&  $uniqend > $new_uniq_end  ));
+                            }
+                            $useslot = $slot;
+                            last;
+                        }
+                        if ($useslot) {
+                            $slotstatus = 'RESERVABLE';
+                            $datemsg = $reservable_now->{$useslot}{'endreserve'};
+                        }
+                    }
+                }
+            }
+            unless ($slotstatus eq 'RESERVABLE') {
+                if ((ref($reservable_future_order) eq 'ARRAY') && (ref($reservable_future) eq 'HASH')) {
+                    if (@{$reservable_future_order} > 0) {
+                        if ((!$checkedin) || (ref($consumed_uniq) ne 'ARRAY')) {
+                            $slotstatus = 'RESERVABLE_LATER';
+                            $datemsg = $reservable_future->{$reservable_future_order->[0]}{'startreserve'};
+                        } else {
+                            my ($uniqstart,$uniqend,$useslot);
+                            if (ref($consumed_uniq) eq 'ARRAY') {
+                                ($uniqstart,$uniqend)=@{$consumed_uniq};
+                            }
+                            foreach my $slot (@{$reservable_future_order}) {
+                                if ($reservable_future->{$slot}{'uniqueperiod'} =~ /^(\d+),(\d+)$/) {
+                                    my ($new_uniq_start,$new_uniq_end) = ($1,$2);
+                                    next if (!
+                                      ($uniqstart < $new_uniq_start && $uniqend < $new_uniq_start) ||
+                                      ($uniqstart > $new_uniq_end   &&  $uniqend > $new_uniq_end  ));
+                                }
+                                $useslot = $slot;
+                                last;
+                            }
+                            if ($useslot) {
+                                $slotstatus = 'RESERVABLE_LATER';
+                                $datemsg = $reservable_future->{$useslot}{'startreserve'};
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return ($slotstatus,$datemsg);
+}
 
 # JB, 9/24/2002: Any changes in this function may require a change
 # in lonnavmaps::resource::getDateStatus.
 sub check_access {
-  my ($id) = @_;
-  my $date ='';
-  my $status;
-  my $datemsg = '';
-  my $lastdate = '';
-  my $temp;
-  my $type;
-  my $passed;
-
-  if ($ENV{'request.state'} eq "construct") {
-    &Apache::lonxml::debug("in construction ignoring dates");
-    $status='CAN_ANSWER';
-    $datemsg='is in under construction';
-    return ($status,$datemsg);
-  }
-
-  &Apache::lonxml::debug("checking for part :$id:");
-  &Apache::lonxml::debug("time:".time);
-  foreach $temp ("opendate","duedate","answerdate") {
-    $lastdate = $date;
-    $date = &Apache::lonnet::EXT("resource.$id.$temp");
-    my $thistype = &Apache::lonnet::EXT("resource.$id.$temp.type");
-    if ($thistype =~ /^(con_lost|no_such_host)/ ||
-	$date     =~ /^(con_lost|no_such_host)/) {
-	$status='UNAVAILABLE';
-	$date="may open later.";
-	return($status,$date);
-    }
-    if ($thistype eq 'date_interval') {
-	if ($temp eq 'opendate') {
-           $date=&Apache::lonnet::EXT("resource.$id.duedate")-$date;
-        }
-        if ($temp eq 'answerdate') {
-           $date=&Apache::lonnet::EXT("resource.$id.duedate")+$date;
-        }
-    }
-    &Apache::lonxml::debug("found :$date: for :$temp:");
-    if ($date eq '') {
-      $date = "an unknown date"; $passed = 0;
-    } elsif ($date eq 'con_lost') {
-      $date = "an indeterminate date"; $passed = 0;
-    } else {
-      if (time < $date) { $passed = 0; } else { $passed = 1; }
-      $date = localtime $date;
+    my ($id,$symb) = @_;
+    my $date ='';
+    my $status;
+    my $datemsg = '';
+    my $lastdate = '';
+    my $type;
+    my $passed;
+
+    if ($env{'request.state'} eq "construct") {
+	if ($env{'form.problemstate'}) {
+	    if ($env{'form.problemstate'} =~ /^CANNOT_ANSWER/) {
+		if ( ! ($env{'form.problemstate'} eq 'CANNOT_ANSWER_correct' 
+			&& &hide_problem_status())) {
+		    return ('CANNOT_ANSWER',
+			    &mt('is in this state due to author settings.'));
+		}
+	    } else {
+		return ($env{'form.problemstate'},
+			&mt('is in this state due to author settings.'));
+	    }
+	}
+	&Apache::lonxml::debug("in construction ignoring dates");
+	$status='CAN_ANSWER';
+	$datemsg=&mt('is in under construction');
+#	return ($status,$datemsg);
+    }
+
+    &Apache::lonxml::debug("checking for part :$id:");
+    &Apache::lonxml::debug("time:".time);
+
+    unless ($symb) {
+        ($symb)=&Apache::lonnet::whichuser();
+    }
+    &Apache::lonxml::debug("symb:".$symb);
+    #if ($env{'request.state'} ne "construct" && $symb ne '') {
+    if ($env{'request.state'} ne "construct") {
+        my $idacc = &Apache::lonnet::EXT("resource.$id.acc",$symb);
+	my $allowed=&Apache::loncommon::check_ip_acc($idacc);
+	if (!$allowed && ($Apache::lonhomework::browse ne 'F')) {
+	    $status='INVALID_ACCESS';
+	    $date=&mt("can not be accessed from your location.");
+	    return($status,$date);
+	}
+	if ($env{'form.grade_imsexport'}) {
+            if (($env{'request.course.id'}) && 
+                (&Apache::lonnet::allowed('mdc',$env{'request.course.id'}))) {
+                return ('SHOW_ANSWER');
+            }
+        }
+	foreach my $temp ("opendate","duedate","answerdate") {
+	    $lastdate = $date;
+	    if ($temp eq 'duedate') {
+		$date = &due_date($id,$symb);
+	    } else {
+		$date = &Apache::lonnet::EXT("resource.$id.$temp",$symb);
+	    }
+	    
+	    my $thistype = &Apache::lonnet::EXT("resource.$id.$temp.type",$symb);
+	    if ($thistype =~ /^(con_lost|no_such_host)/ ||
+		$date     =~ /^(con_lost|no_such_host)/) {
+		$status='UNAVAILABLE';
+		$date=&mt("may open later.");
+		return($status,$date);
+	    }
+	    if ($thistype eq 'date_interval') {
+		if ($temp eq 'opendate') {
+		    $date=&Apache::lonnet::EXT("resource.$id.duedate",$symb)-$date;
+		}
+		if ($temp eq 'answerdate') {
+		    $date=&Apache::lonnet::EXT("resource.$id.duedate",$symb)+$date;
+		}
+	    }
+	    &Apache::lonxml::debug("found :$date: for :$temp:");
+	    if ($date eq '') {
+		$date = &mt("an unknown date"); $passed = 0;
+	    } elsif ($date eq 'con_lost') {
+		$date = &mt("an indeterminate date"); $passed = 0;
+	    } else {
+		if (time < $date) { $passed = 0; } else { $passed = 1; }
+		$date = &Apache::lonlocal::locallocaltime($date);
+	    }
+	    if (!$passed) { $type=$temp; last; }
+	}
+	&Apache::lonxml::debug("have :$type:$passed:");
+	if ($passed) {
+	    $status='SHOW_ANSWER';
+	    $datemsg=$date;
+	} elsif ($type eq 'opendate') {
+	    $status='CLOSED';
+	    $datemsg = &mt('will open on [_1]',$date);
+	} elsif ($type eq 'duedate') {
+	    $status='CAN_ANSWER';
+	    $datemsg = &mt('is due at [_1]',$date);
+	} elsif ($type eq 'answerdate') {
+	    $status='CLOSED';
+	    $datemsg = &mt('was due on [_1], and answers will be available on [_2]',
+                               $lastdate,$date);
+	}
+    }
+    if ($status eq 'CAN_ANSWER' ||
+	(($Apache::lonhomework::browse eq 'F') && ($status eq 'CLOSED'))) {
+	#check #tries, and if correct.
+	my $tries = $Apache::lonhomework::history{"resource.$id.tries"};
+	my $maxtries = &Apache::lonnet::EXT("resource.$id.maxtries",$symb);
+	if ( $tries eq '' ) { $tries = '0'; }
+	if ( $maxtries eq '' && 
+	     $env{'request.state'} ne 'construct') { $maxtries = '2'; } 
+	if ($maxtries && $tries >= $maxtries) { $status = 'CANNOT_ANSWER'; }
+	# if (correct and show prob status) or excused then CANNOT_ANSWER
+	if ( ($Apache::lonhomework::history{"resource.$id.solved"}=~/^correct/)
+	      && (&show_problem_status()) ) {
+            if (($Apache::lonhomework::history{"resource.$id.awarded"} >= 1) ||
+                (&Apache::lonnet::EXT("resource.$id.retrypartial",$symb) !~/^1|on|yes$/i)) {
+	        $status = 'CANNOT_ANSWER';
+            }
+        } elsif ($Apache::lonhomework::history{"resource.$id.solved"}=~/^excused/) {
+	    $status = 'CANNOT_ANSWER';
+	}
+	if ($status eq 'CANNOT_ANSWER'
+	    && &show_answer_problem_status()) {
+	    $status = 'SHOW_ANSWER';
+	}
     }
-    if (!$passed) { $type=$temp; last; }
-  }
-  &Apache::lonxml::debug("have :$type:$passed:");
-  if ($passed) {
-    $status='SHOW_ANSWER';
-    $datemsg=$date;
-  } elsif ($type eq 'opendate') {
-    $status='CLOSED';
-    $datemsg = "will open on $date";
-  } elsif ($type eq 'duedate') {
-    $status='CAN_ANSWER';
-    $datemsg = "is due at $date";
-  } elsif ($type eq 'answerdate') {
-    $status='CLOSED';
-    $datemsg = "was due on $lastdate, and answers will be available on $date";
-  }
-  if ($status eq 'CAN_ANSWER') {
-    #check #tries, and if correct.
-    my $tries = $Apache::lonhomework::history{"resource.$id.tries"};
-    my $maxtries = &Apache::lonnet::EXT("resource.$id.maxtries");
-    if ( $tries eq '' ) { $tries = '0'; }
-    if ( $maxtries eq '' ) { $maxtries = '2'; } 
-    if ($tries >= $maxtries) { $status = 'CANNOT_ANSWER'; }
-    # if (correct and show prob status) or excused then CANNOT_ANSWER
-    if(($Apache::lonhomework::history{"resource.$id.solved"}=~/^correct/
-	&&
-	lc($Apache::lonhomework::problemstatus) ne 'no')
-       ||
-       $Apache::lonhomework::history{"resource.$id.solved"}=~/^excused/) {
-	$status = 'CANNOT_ANSWER';
+    if ($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER') {
+	my @interval=&Apache::lonnet::EXT("resource.$id.interval",$symb);
+	&Apache::lonxml::debug("looking for interval @interval");
+	if ($interval[0]=~ /^\d+/) {
+	    my $first_access=&Apache::lonnet::get_first_access($interval[1],$symb);
+	    &Apache::lonxml::debug("looking for accesstime $first_access");
+	    if (!$first_access) {
+		$status='NOT_YET_VIEWED';
+		my $due_date = &due_date($id,$symb);
+		my $seconds_left = $due_date - time;
+		my ($timelimit) = ($interval[0] =~ /^(\d+)/);
+		if ($seconds_left > $timelimit || $due_date eq '') {
+		    $seconds_left = $timelimit;
+		}
+		$datemsg=&seconds_to_human_length($seconds_left);
+	    }
+	}
     }
-  }
 
   #if (($status ne 'CLOSED') && ($Apache::lonhomework::type eq 'exam') &&
   #    (!$Apache::lonhomework::history{"resource.0.outtoken"})) {
   #    return ('UNCHECKEDOUT','needs to be checked out');
   #}
 
+    &Apache::lonxml::debug("sending back :$status:$datemsg:");
+    if (($Apache::lonhomework::browse eq 'F') && ($status eq 'CLOSED')) {
+	&Apache::lonxml::debug("should be allowed to browse a resource when closed");
+	$status='CAN_ANSWER';
+	$datemsg=&mt('is closed but you are allowed to view it');
+    }
 
-  &Apache::lonxml::debug("sending back :$status:$datemsg:");
-  if (($Apache::lonhomework::browse eq 'F') && ($status eq 'CLOSED')) {
-    &Apache::lonxml::debug("should be allowed to browse a resource when closed");
-    $status='CAN_ANSWER';
-    $datemsg='is closed but you are allowed to view it';
-  }
+    return ($status,$datemsg);
+}
+# this should work exactly like the copy in lonnavmaps.pm
+sub due_date {
+    my ($part_id,$symb,$udom,$uname)=@_;
+    my $date;
+    my @interval= &Apache::lonnet::EXT("resource.$part_id.interval",$symb,
+				       $udom,$uname);
+    &Apache::lonxml::debug("looking for interval $part_id $symb @interval");
+    my $due_date= &Apache::lonnet::EXT("resource.$part_id.duedate",$symb,
+				       $udom,$uname);
+    &Apache::lonxml::debug("looking for due_date $part_id $symb $due_date");
+    if ($interval[0] =~ /\d+/) {
+	my $first_access=&Apache::lonnet::get_first_access($interval[1],$symb);
+	&Apache::lonxml::debug("looking for first_access $first_access ($interval[1])");
+	if (defined($first_access)) {
+	    my ($timelimit) = ($interval[0] =~ /^(\d+)/);
+	    my $interval = $first_access+$timelimit;
+	    $date = (!$due_date || $interval < $due_date) ? $interval
+                                                          : $due_date;
+	} else {
+	    $date = $due_date;
+	}
+    } else {
+	$date = $due_date;
+    }
+    return $date;
+}
+
+sub seconds_to_human_length {
+    my ($length)=@_;
 
-  return ($status,$datemsg);
+    my $seconds=$length%60; $length=int($length/60);
+    my $minutes=$length%60; $length=int($length/60);
+    my $hours=$length%24;   $length=int($length/24);
+    my $days=$length;
+
+    my $timestr;
+    if ($days > 0) { $timestr.=&mt('[quant,_1,day]',$days); }
+    if ($hours > 0) { $timestr.=($timestr?", ":"").
+			  &mt('[quant,_1,hour]',$hours); }
+    if ($minutes > 0) { $timestr.=($timestr?", ":"").
+			    &mt('[quant,_1,minute]',$minutes); }
+    if ($seconds > 0) { $timestr.=($timestr?", ":"").
+			    &mt('[quant,_1,second]',$seconds); }
+    return $timestr;
 }
 
 sub showhash {
-  my (%hash) = @_;
-  &showhashsubset(\%hash,'.');
-  return '';
+    my (%hash) = @_;
+    &showhashsubset(\%hash,'.');
+    return '';
 }
 
 sub showarray {
     my ($array)=@_;
     my $string="(";
     foreach my $elm (@{ $array }) {
-	if (ref($elm)) {
-	    if ($elm =~ /ARRAY/ ) {
-		$string.=&showarray($elm);
-	    }
+	if (ref($elm) eq 'ARRAY') {
+	    $string.=&showarray($elm);
+	} elsif (ref($elm) eq 'HASH') {
+	    $string.= "HASH --- \n<br />";
+	    $string.= &showhashsubset($elm,'.');
 	} else {
 	    $string.="$elm,"
 	}
@@ -270,119 +778,236 @@ sub showarray {
 }
 
 sub showhashsubset {
-  my ($hash,$keyre) = @_;
-  my $resultkey;
-  foreach $resultkey (sort keys %$hash) {
-    if ($resultkey =~ /$keyre/) {
-      if (ref($$hash{$resultkey})) {
-	if ($$hash{$resultkey} =~ /ARRAY/ ) {
+    my ($hash,$keyre) = @_;
+    my $resultkey;
+    foreach $resultkey (sort(keys(%$hash))) {
+	if ($resultkey !~ /$keyre/) { next; }
+	if (ref($$hash{$resultkey})  eq 'ARRAY' ) {
 	    &Apache::lonxml::debug("$resultkey ---- ".
 				   &showarray($$hash{$resultkey}));
-	} elsif ($$hash{$resultkey} =~ /HASH/ ) {
+	} elsif (ref($$hash{$resultkey}) eq 'HASH' ) {
 	    &Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}");
 	    &showhashsubset($$hash{$resultkey},'.');
 	} else {
 	    &Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}");
 	}
-      } else {
-	&Apache::lonxml::debug("$resultkey ---- $$hash{$resultkey}");
-      }
-    }
-  }
-  &Apache::lonxml::debug("\n<br />restored values^</br>\n");
-  return '';
+    }
+    &Apache::lonxml::debug("\n<br />restored values^</br>\n");
+    return '';
 }
 
 sub setuppermissions {
-  $Apache::lonhomework::browse= &Apache::lonnet::allowed('bre',$ENV{'request.filename'});
-  my $viewgrades = &Apache::lonnet::allowed('vgr',$ENV{'request.course.id'});
-  if (! $viewgrades && 
-      exists($ENV{'request.course.sec'}) && 
-      $ENV{'request.course.sec'} !~ /^\s*$/) {
-      $viewgrades = &Apache::lonnet::allowed('vgr',$ENV{'request.course.id'}.
-                                               '/'.$ENV{'request.course.sec'});
-  }
-  $Apache::lonhomework::viewgrades = $viewgrades;
-  return ''
+    $Apache::lonhomework::browse= &Apache::lonnet::allowed('bre',$env{'request.filename'});
+    unless ($Apache::lonhomework::browse eq 'F') {
+        $Apache::lonhomework::browse=&Apache::lonnet::allowed('bro',$env{'request.filename'}); 
+    }
+    my $viewgrades = &Apache::lonnet::allowed('vgr',$env{'request.course.id'});
+    if (! $viewgrades && 
+	exists($env{'request.course.sec'}) && 
+	$env{'request.course.sec'} !~ /^\s*$/) {
+	$viewgrades = &Apache::lonnet::allowed('vgr',$env{'request.course.id'}.
+                                               '/'.$env{'request.course.sec'});
+        if ($viewgrades) {
+            $Apache::lonhomework::viewgradessec = $env{'request.course.sec'};
+        }
+    }
+    $Apache::lonhomework::viewgrades = $viewgrades;
+
+    if ($Apache::lonhomework::browse eq 'F' && 
+	$env{'form.devalidatecourseresdata'} eq 'on') {
+	my (undef,$courseid) = &Apache::lonnet::whichuser();
+	&Apache::lonnet::devalidatecourseresdata($env{"course.$courseid.num"},
+					      $env{"course.$courseid.domain"});
+    }
+
+    my $modifygrades = &Apache::lonnet::allowed('mgr',$env{'request.course.id'});
+    if (! $modifygrades && 
+	exists($env{'request.course.sec'}) && 
+	$env{'request.course.sec'} !~ /^\s*$/) {
+	$modifygrades = 
+	    &Apache::lonnet::allowed('mgr',$env{'request.course.id'}.
+				     '/'.$env{'request.course.sec'});
+        if ($modifygrades) {
+            $Apache::lonhomework::modifygradessec = $env{'request.course.sec'};
+        }
+    }
+    $Apache::lonhomework::modifygrades = $modifygrades;
+
+    my $queuegrade = &Apache::lonnet::allowed('mqg',$env{'request.course.id'});
+    if (! $queuegrade && 
+	exists($env{'request.course.sec'}) && 
+	$env{'request.course.sec'} !~ /^\s*$/) {
+	$queuegrade = 
+	    &Apache::lonnet::allowed('qgr',$env{'request.course.id'}.
+				     '/'.$env{'request.course.sec'});
+    }
+    $Apache::lonhomework::queuegrade = $queuegrade;
+    return '';
+}
+
+sub unset_permissions {
+    undef($Apache::lonhomework::queuegrade);
+    undef($Apache::lonhomework::modifygrades);
+    undef($Apache::lonhomework::modifygradessec);
+    undef($Apache::lonhomework::viewgrades);
+    undef($Apache::lonhomework::viewgradessec);
+    undef($Apache::lonhomework::browse);
 }
 
 sub setupheader {
     my $request=$_[0];
-    if ($ENV{'browser.mathml'}) {
-	$request->content_type('text/xml');
-    } else {
-	$request->content_type('text/html');
-    }
-    $request->content_encoding('UTF-8');
+    &Apache::loncommon::content_type($request,'text/html');
     if (!$Apache::lonxml::debug && ($ENV{'REQUEST_METHOD'} eq 'GET')) {
 	&Apache::loncommon::no_cache($request);
     }
+#    $request->set_last_modified(&Apache::lonnet::metadata($request->uri,
+#							  'lastrevisiondate'));
     $request->send_http_header;
     return OK if $request->header_only;
     return ''
 }
 
 sub handle_save_or_undo {
-  my ($request,$problem,$result) = @_;
-  my $file    = &Apache::lonnet::filelocation("",$request->uri);
-  my $filebak =$file.".bak";
-  my $filetmp =$file.".tmp";
-  my $error=0;
+    my ($request,$problem,$result,$getobjref) = @_;
 
-  if ($ENV{'form.Undo'} eq 'undo') {
+    my $file    = &Apache::lonnet::filelocation("",$request->uri);
+    my $filebak =$file.".bak";
+    my $filetmp =$file.".tmp";
     my $error=0;
-    if (!copy($file,$filetmp)) { $error=1; }
-    if ((!$error) && (!copy($filebak,$file))) { $error=1; }
-    if ((!$error) && (!move($filetmp,$filebak))) { $error=1; }
-    if (!$error) {
-      $request->print("<p><b>Undid changes, Switched $filebak and $file</b></p>");
-    } else {
-      $request->print("<p><font color=\"red\" size=\"+1\"><b>Unable to undo, unable to switch $filebak and $file</b></font></p>");
-      $error=1;
-    }
-  } else {
-    my $fs=Apache::File->new(">$filebak");
-    if (defined($fs)) {
-      print $fs $$problem;
-      $request->print("<b>Making Backup to $filebak</b><br />");
-    } else {
-      $request->print("<font color=\"red\" size=\"+1\"><b>Unable to make backup $filebak</b></font>");
-      $error=2;
-    }
-    my $fh=Apache::File->new(">$file");
-    if (defined($fh)) {
-      print $fh $$result;
-      $request->print("<b>Saving Modifications to $file</b><br />");
+    if (($env{'form.problemmode'} eq 'undo') || ($env{'form.problemmode'} eq 'undoxml')) {
+	my $error=0;
+	if (!&File::Copy::copy($file,$filetmp)) { $error=1; }
+	if ((!$error) && (!&File::Copy::copy($filebak,$file))) { $error=1; }
+	if ((!$error) && (!&File::Copy::move($filetmp,$filebak))) { $error=1; }
+	if (!$error) {
+	    &Apache::lonxml::info("<p><b>".
+				  &mt("Undid changes, Switched [_1] and [_2]",
+				      '<span class="LC_filename">'.$filebak.
+				      '</span>',
+				      '<span class="LC_filename">'.$file.
+				      '</span>')."</b></p>");
+	} else {
+	    &Apache::lonxml::info("<p><span class=\"LC_error\">".
+				  &mt("Unable to undo, unable to switch [_1] and [_2]",
+				      '<span class="LC_filename">'.
+				      $filebak.'</span>',
+				      '<span class="LC_filename">'.
+				      $file.'</span>')."</span></p>");
+	    $error=1;
+	}
     } else {
-      $request->print("<font color=\"red\" size=\"+1\"><b>Unable to write to $file</b></font>");
-      $error|=4;
+        &Apache::lonnet::correct_line_ends($result);
+
+	my $fs=Apache::File->new(">$filebak");
+	if (defined($fs)) {
+	    print $fs $$problem;
+	} else {
+	    &Apache::lonxml::info("<span class=\"LC_error\">".
+				  &mt("Unable to make backup [_1]",
+				      '<span class="LC_filename">'.
+				      $filebak.'</span>')."</span>");
+	    $error=2;
+	}
+	my $fh=Apache::File->new(">$file");
+	if (defined($fh)) {
+	    print $fh $$result;
+            if (ref($getobjref) eq 'SCALAR') {
+                if ($file =~ m{([^/]+)\.(html?)$}) {
+                    my $fname = $1;
+                    my $ext = $2;
+                    my $path = $file;
+                    $path =~ s/\Q$fname\E\.\Q$ext\E$//; 
+                    my (%allfiles,%codebase);
+                    &Apache::lonnet::extract_embedded_items($file,\%allfiles,
+                                                           \%codebase,$result);
+                    if (keys(%allfiles) > 0) {
+                        my $url = $request->uri;
+                        my $state = <<STATE;
+    <input type="hidden" name="action" value="upload_embedded" />
+    <input type="hidden" name="url" value="$url" />
+STATE
+                        $$getobjref = "<h3>".&mt("Reference Warning")."</h3>".
+                                      "<p>".&mt("Completed upload of the file. This file contained references to other files.")."</p>".
+                                      "<p>".&mt("Please select the locations from which the referenced files are to be uploaded.")."</p>".
+                                      &Apache::loncommon::ask_for_embedded_content($url,$state,\%allfiles,\%codebase,
+                                      {'error_on_invalid_names'   => 1,
+                                       'ignore_remote_references' => 1,});
+                    }
+                }
+            }
+	} else {
+	    &Apache::lonxml::info('<span class="LC_error">'.
+				  &mt("Unable to write to [_1]",
+				      '<span class="LC_filename">'.
+				      $file.'</span>').
+				  '</span>');
+	    $error|=4;
+	}
     }
-  }
-  return $error;
+    return $error;
 }
 
 sub analyze_header {
     my ($request) = @_;
-    my $result.='<html>
-            <head><title>Analyzing a problem</title></head>
-            <body bgcolor="#FFFFFF">
-            <form name="lonhomework" method="POST" action="'.
-	      $ENV{'request.uri'}.'">
-            <input type="submit" name="problemmode" value="EditXML" />
-            <input type="submit" name="problemmode" value="Edit" />
-            <hr />
-            <input type="submit" name="submit" value="View" />
+    my $js = &Apache::lonxml::setmode_javascript();
+
+    # Breadcrumbs
+    my $text = 'Authoring Space';
+    my $href = &Apache::loncommon::authorspace($request->uri);
+    if ($env{'request.course.id'}) {
+        my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+        my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+        if ($href eq "/priv/$cdom/$cnum/") {
+            $text = 'Course Authoring Space';
+        }
+    }
+    my $brcrum = [{'href' => $href,
+                   'text' => $text},
+                  {'href' => '',
+                   'text' => 'Problem Testing'},
+                  {'href' => '',
+                   'text' => 'Analyzing a problem'}];
+
+    my $result =
+        &Apache::loncommon::start_page('Analyzing a problem',
+                                       $js,
+                                       {'bread_crumbs' => $brcrum,})
+       .&Apache::loncommon::head_subbox(
+                &Apache::loncommon::CSTR_pageheader());
+    my %lt = &Apache::lonlocal::texthash(
+                 edit => 'Edit',
+                 editxml => 'EditXML',
+             );
+    $result .= 
+	    '<form name="lonhomework" method="post" action="'.
+	    &HTML::Entities::encode($env{'request.uri'},'<>&"').'">'.
+            '<input type="hidden" name="problemmode" value="'.
+            $env{'form.problemmode'}.'" />'.
+	    &Apache::structuretags::remember_problem_state().'
+            <div class="LC_edit_problem_analyze_header">';
+     my %editors = &Apache::loncommon::permitted_editors();
+     foreach my $item ('editxml','edit') {
+         next unless ($editors{$item});
+         $result .= '<input type="button" name="submitmode" value="'.$lt{$item}.'" '.
+                    'onclick="javascript:setmode(this.form,'."'$item'".')" />'.
+                    "\n";
+     }
+     $result .=
+            '<hr />
+            <input type="button" name="submitmode" value="'.&mt("View").'" '.
+            'onclick="javascript:setmode(this.form,'."'view'".')" />
             <hr />
-            List of possible answers:
-            </form>';
+            </div>'
+            .&Apache::lonxml::message_location().
+            '</form>';
+    &Apache::lonxml::add_messages(\$result);
     $request->print($result);
     $request->rflush();
 }
 
 sub analyze_footer {
     my ($request) = @_;
-    my $result='</body></html>';
-    $request->print($result);
+    $request->print(&Apache::loncommon::end_page());
     $request->rflush();
 }
 
@@ -391,23 +1016,23 @@ sub analyze {
     &Apache::lonxml::debug("Analyze");
     my $result;
     my %overall;
+    my %seedexample;
     my %allparts;
-    my $rndseed=$ENV{'form.rndseed'};
+    my $rndseed=$env{'form.rndseed'};
     &analyze_header($request);
     my %prog_state=
-	&Apache::lonhtmlcommon::Create_PrgWin($request,'Analyze Progress',
-					      'Getting Problem Variants',
-					      $ENV{'form.numtoanalyze'});
-    for(my $i=1;$i<$ENV{'form.numtoanalyze'}+1;$i++) {
-	&Apache::lonhtmlcommon::Increment_PrgWin($request,\%prog_state,
-						 'last problem');
+	&Apache::lonhtmlcommon::Create_PrgWin($request,$env{'form.numtoanalyze'});
+    for(my $i=1;$i<$env{'form.numtoanalyze'}+1;$i++) {
+	&Apache::lonhtmlcommon::Increment_PrgWin($request,\%prog_state,'last problem');
+	if (&Apache::loncommon::connection_aborted($request)) { return; }
+        my $thisseed=$i+$rndseed;
 	my $subresult=&Apache::lonnet::ssi($request->uri,
 					   ('grade_target' => 'analyze'),
-					   ('rndseed' => $i+$rndseed));
+					   ('rndseed' => $thisseed));
 	(my $garbage,$subresult)=split(/_HASH_REF__/,$subresult,2);
 	my %analyze=&Apache::lonnet::str2hash($subresult);
 	my @parts;
-	if (defined(@{ $analyze{'parts'} })) {
+        if (ref($analyze{'parts'}) eq 'ARRAY') {
 	    @parts=@{ $analyze{'parts'} };
 	}
 	foreach my $part (@parts) {
@@ -415,38 +1040,89 @@ sub analyze {
 	    if ($analyze{$part.'.type'} eq 'numericalresponse'	||
 		$analyze{$part.'.type'} eq 'stringresponse'	||
 		$analyze{$part.'.type'} eq 'formularesponse'   ) {
-		push( @{ $overall{$part.'.answer'} },
-		      [@{ $analyze{$part.'.answer'} }]);
+		foreach my $name (keys(%{ $analyze{$part.'.answer'} })) {
+		    my $i=0;
+		    foreach my $answer_part (@{ $analyze{$part.'.answer'}{$name} }) {
+			push( @{ $overall{$part.'.answer'}[$i] },
+			      $answer_part);
+			my $concatanswer= join("\0",@{ $answer_part });
+			if (($concatanswer eq '') || ($concatanswer=~/^\@/)) {
+			    $answer_part = ['<span class="LC_error">'.&mt('Error').'</span>'];
+			}
+			$seedexample{join("\0",$part,$i,@{$answer_part})}=
+			    $thisseed;
+			$i++;
+		    }
+		}
+		if (!keys(%{ $analyze{$part.'.answer'} })) {
+		    my $answer_part = 
+			['<span class="LC_error">'.&mt('Error').'</span>'];
+		    $seedexample{join("\0",$part,0,@{$answer_part})}=
+			$thisseed;
+		    push( @{ $overall{$part.'.answer'}[0] },
+			  $answer_part);
+		}
 	    }
 	}
     }
-    &Apache::lonhtmlcommon::Update_PrgWin($request,\%prog_state,
-					  'Analyzing Results');
+    &Apache::lonhtmlcommon::Update_PrgWin($request,\%prog_state,&mt('Analyzing Results'));
+    $request->print('<hr />'
+                   .'<h3>'
+                   .&mt('List of possible answers')
+                   .'</h3>'
+    );
     foreach my $part (sort(keys(%allparts))) {
-	if (defined(@{ $overall{$part.'.answer'} })) {
-	    my $num_cols=scalar(@{ $overall{$part.'.answer'}->[0] });
-	    $request->print('<table><tr><td colspan="'.($num_cols+1).'">Part '.$part.'</td></tr>');
-	    my %frequency;
-	    foreach my $answer (sort {$a->[0] <=> $b->[0]} (@{ $overall{$part.'.answer'} })) {
-		$frequency{join("\0",@{ $answer })}++;
-	    }
-	    $request->print('<tr><td colspan="'.($num_cols).'">Answer</td><td>Frequency</td></tr>');
-	    foreach my $answer (sort {(split("\0",$a))[0] <=> (split("\0",$b))[0]} (keys(%frequency))) {
-		$request->print('<tr><td align="right">'.
-				join('</td><td align="right">',split("\0",$answer)).
-				'</td><td>('.$frequency{$answer}.
-				')</td></tr>');
+        if ((ref($overall{$part.'.answer'}) eq 'ARRAY') &&
+            (@{$overall{$part.'.answer'}} > 0)) {
+	    for (my $i=0;$i<scalar(@{ $overall{$part.'.answer'} });$i++) {
+		my $num_cols=scalar(@{ $overall{$part.'.answer'}[$i][0] });
+                $request->print(&Apache::loncommon::start_data_table()
+                               .&Apache::loncommon::start_data_table_header_row()
+                               .'<th colspan="'.($num_cols+1).'">'
+                               .&mt('Part').' '.$part
+                );
+		if (scalar(@{ $overall{$part.'.answer'} }) > 1) {
+		    $request->print(' '.&mt('Answer [_1]',$i+1));
+		}
+		$request->print('</th>'
+                               .&Apache::loncommon::end_data_table_header_row()
+                );
+		my %frequency;
+		foreach my $answer (sort {$a->[0] <=> $b->[0]} (@{ $overall{$part.'.answer'}[$i] })) {
+		    $frequency{join("\0",@{ $answer })}++;
+		}
+                $request->print(&Apache::loncommon::start_data_table_header_row()
+                               .'<th colspan="'.($num_cols).'">'.&mt('Answer').'</th>'
+                               .'<th>'.&mt('Frequency').'<br />'
+                               .'('.&mt('click for example').')</th>'
+                               .&Apache::loncommon::end_data_table_header_row()
+                );
+		foreach my $answer (sort {(split("\0",$a))[0] <=> (split("\0",$b))[0]} (keys(%frequency))) {
+                    $request->print(&Apache::loncommon::start_data_table_row()
+                                   .'<td>'
+                                   .join('</td><td>',split("\0",$answer))
+				   .'</td>'
+                                   .'<td>'
+                                   .'<a href="'.$request->uri.'?rndseed='.$seedexample{join("\0",$part,$i,$answer)}.'">'.$frequency{$answer}.'</a>'
+				   .'</td>'
+                                   .&Apache::loncommon::end_data_table_row()
+                    );
+		}
+                $request->print(&Apache::loncommon::end_data_table());
 	    }
-	    $request->print('</table>');
 	} else {
-	    $request->print('<p>Part '.$part.
-			    ' is not analyzable at this time</p>');
+            $request->print('<p class="LC_warning">'
+                           .&mt('Response [_1] is not analyzable at this time.',$part)
+			   .'</p>'
+            );
 	}
     }
     if (scalar(keys(%allparts)) == 0 ) {
-	$request->print('<p>Found no analyzable parts in this problem,
-                         currently only Numerical, Formula and String response
-                         styles are supported.</p>');
+        $request->print('<p class="LC_warning">'
+                       .&mt('Found no analyzable responses in this problem.'
+                           .' Currently only Numerical, Formula and String response styles are supported.')
+                       .'</p>'
+        );
     }
     &Apache::lonhtmlcommon::Close_PrgWin($request,\%prog_state);
     &analyze_footer($request);
@@ -454,262 +1130,1059 @@ sub analyze {
     return $result;
 }
 
+{
+    my $show_problem_status;
+    sub reset_show_problem_status {
+	undef($show_problem_status);
+    }
+
+    sub set_show_problem_status {
+	my ($new_status) = @_;
+	$show_problem_status = lc($new_status);
+    }
+
+    sub hide_problem_status {
+	return ($show_problem_status eq 'no'
+		|| $show_problem_status eq 'no_feedback_ever');
+    }
+
+    sub show_problem_status {
+	return ($show_problem_status eq 'yes'
+		|| $show_problem_status eq 'answer'
+		|| $show_problem_status eq '');
+    }
+    
+    sub show_some_problem_status {
+	return ($show_problem_status eq 'no');
+    }
+
+    sub show_no_problem_status {
+	return ($show_problem_status eq 'no_feedback_ever');
+    }
+  
+    sub show_answer_problem_status {
+	return ($show_problem_status eq 'answer');
+    }
+}
+
 sub editxmlmode {
-  my ($request,$file) = @_;
-  my $result;
-  my $problem=&Apache::lonnet::getfile($file);
-  if ($problem eq -1) {
-    &Apache::lonxml::error("<b> Unable to find <i>$file</i></b>");
-    $problem='';
-  }
-  if (defined($ENV{'form.editxmltext'}) || defined($ENV{'form.Undo'})) {
-    my $error=&handle_save_or_undo($request,\$problem,
-				   \$ENV{'form.editxmltext'});
-    if (!$error) { $problem=&Apache::lonnet::getfile($file); }
-  }
-  &Apache::lonhomework::showhashsubset(\%ENV,'^form');
-  if ( $ENV{'form.submit'} eq 'Submit Changes and View' ) {
-    &Apache::lonhomework::showhashsubset(\%ENV,'^form');
-    $ENV{'form.problemmode'}='View';
-    &renderpage($request,$file);
-  } else {
-    my ($rows,$cols) = &Apache::edit::textarea_sizes(\$problem);
-    my $xml_help = Apache::loncommon::helpLatexCheatsheet("Problem_Editor_XML_Index",
-							  "Problem Editing Help");
-    if ($cols > 80) { $cols = 80; }
-    if ($cols < 70) { $cols = 70; }
-    if ($rows < 20) { $rows = 20; }
-    $result.='<html><body bgcolor="#FFFFFF">
-            <form name="lonhomework" method="POST" action="'.
-	      $ENV{'request.uri'}.'">
-            <input type="hidden" name="problemmode" value="EditXML" />
-            <input type="submit" name="problemmode" value="Discard Edits and View" />
-            <input type="submit" name="problemmode" value="Edit" />
-            <hr />
-            <input type="submit" name="submit" value="Submit Changes" />
-            <input type="submit" name="submit" value="Submit Changes and View" />
-            <input type="submit" name="Undo" value="undo" />
-            <hr />
-            ' . $xml_help . '
-            <textarea rows="'.$rows.'" cols="'.$cols.'" name="editxmltext">'.
-	      &HTML::Entities::encode($problem).'</textarea>
-            </form></body></html>';
+    my ($request,$file) = @_;
+    my $result;
+    my $problem=&Apache::lonnet::getfile($file);
+    if ($problem eq -1) {
+	&Apache::lonxml::error(
+            '<p class="LC_error">'
+           .&mt('Unable to find [_1]',
+                '<span class="LC_filename">'.$file.'</span>')
+           .'</p>');
+
+	$problem='';
+    }
+    if (($env{'form.problemmode'} eq 'saveeditxml') ||
+        ($env{'form.problemmode'} eq 'saveviewxml') ||
+        ($env{'form.problemmode'} eq 'undoxml')) {
+	my $error=&handle_save_or_undo($request,\$problem,
+				       \$env{'form.editxmltext'});
+	if (!$error) { $problem=&Apache::lonnet::getfile($file); }
+    }
+    &Apache::lonhomework::showhashsubset(\%env,'^form');
+    if ($env{'form.problemmode'} eq 'saveviewxml') {
+	&Apache::lonhomework::showhashsubset(\%env,'^form');
+	$env{'form.problemmode'}='view';
+	&renderpage($request,$file);
+    } else {
+	my ($rows,$cols) = &Apache::edit::textarea_sizes(\$problem);
+	if ($cols > 80) { $cols = 80; }
+	if ($cols < 70) { $cols = 70; }
+	if ($rows < 20) { $rows = 20; }
+	my $js =
+	    &Apache::edit::js_change_detection(). 
+	    &Apache::loncommon::resize_textarea_js().
+            &Apache::lonxml::setmode_javascript().
+            &Apache::lonhtmlcommon::dragmath_js("EditMathPopup");
+
+    # Breadcrumbs
+    my $text = 'Authoring Space';
+    my $href = &Apache::loncommon::authorspace($request->uri);
+    if ($env{'request.course.id'}) {
+        my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+        my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+        if ($href eq "/priv/$cdom/$cnum/") {
+            $text = 'Course Authoring Space';
+        }
+    }
+    my $brcrum = [{'href' => $href,
+                   'text' => $text},
+                  {'href' => '',
+                   'text' => 'Problem Editing'}];
+
+	my $start_page = 
+	    &Apache::loncommon::start_page(&mt("EditXML [_1]",$file),$js,
+					   {'no_auto_mt_title' => 1,
+					    'only_body'        => 0,
+					    'add_entries'      => {
+						'onresize' => q[resize_textarea('LC_editxmltext','LC_aftertextarea')],
+						'onload'   => q[resize_textarea('LC_editxmltext','LC_aftertextarea')],
+                                                                  },
+                                                'bread_crumbs' => $brcrum,
+                                             });
+
+    $result=$start_page
+           .&Apache::loncommon::head_subbox(
+                &Apache::loncommon::CSTR_pageheader());
+	$result.=&renderpage($request,$file,['no_output_web'],1).
+            '<form '.&Apache::edit::form_change_detection().' name="lonhomework" method="post" action="'.
+	    &HTML::Entities::encode($env{'request.uri'},'<>&"').'">'.
+	    &Apache::structuretags::remember_problem_state().'
+            <div class="LC_edit_problem_header">
+              <div class="LC_edit_problem_header_title">'.
+                &mt('Problem Editing').' '.&Apache::loncommon::help_open_topic('Problem_Editor_XML_Index').
+              '</div><div class="LC_edit_actionbar" id="actionbar">';
+
+    $result.='<input type="hidden" name="problemmode" value="saveedit" />'.
+                  &Apache::structuretags::problem_edit_buttons('editxml');
+    $result.='<div>';
+
+    $result .= '<ol class="LC_primary_menu" style="display:inline-block;font-size:90%;vertical-align:middle;">';
+
+    my $nocodemirror = &Apache::loncommon::nocodemirror();
+    unless ($nocodemirror) {
+        # dropdown menus
+        $result .= Apache::lonmenu::create_submenu("#", "",
+            &mt("Problem Templates"), template_dropdown_datastructure());
+
+        $result .= Apache::lonmenu::create_submenu("#", "",
+            &mt("Response Types"), responseblock_dropdown_datastructure());
+
+        $result .= Apache::lonmenu::create_submenu("#", "",
+            &mt("Conditional Blocks"), conditional_scripting_datastructure());
+
+        $result .= Apache::lonmenu::create_submenu("#", "",
+            &mt("Miscellaneous"), misc_datastructure());
+    }
+
+    $result .= Apache::lonmenu::create_submenu("#", "",
+        &mt("Help") . ' <img src="/adm/help/help.png" alt="' . &mt("Help") .
+        '" style="vertical-align:text-bottom; height: auto; margin:0; "/>',
+        helpmenu_datastructure(),"");
+
+    $result.="</ol></div>";
+
+    $result .= '</div></div>' .
+        &Apache::lonxml::message_location() .
+        &Apache::loncommon::xmleditor_js() .
+        '<textarea ' . &Apache::edit::element_change_detection() .
+        ' rows="'.$rows.'" cols="'.$cols.'" style="width:100%" ' .
+        ' name="editxmltext" id="LC_editxmltext">' .
+        &HTML::Entities::encode($problem,'<>&"') .
+        '</textarea> <div id="LC_aftertextarea"> </div> </form>';
+
+    my $resource = $env{'request.ambiguous'};
+    unless ($nocodemirror) {
+        $result .= '<link rel="stylesheet" href="/adm/codemirror/codemirror-combined-xml.css">
+        <script src="/adm/codemirror/codemirror-compressed-xml.js"></script>
+        <script>
+            CodeMirror.defineMode("mixedmode", function(config) {
+                return CodeMirror.multiplexingMode(
+                    CodeMirror.getMode(config, "xml"),
+                    {
+                        open: "\<script type=\"loncapa/perl\"\>", close: "\</script\>",
+                        mode: CodeMirror.getMode(config, "perl"),
+                        delimStyle: "tag",
+                    }
+              );
+            });
+            var cm = CodeMirror.fromTextArea(document.getElementById("LC_editxmltext"),
+            {
+                mode: "mixedmode",
+                lineWrapping: true,
+                lineNumbers: true,
+                tabSize: 4,
+                indentUnit: 4,
+
+                autoCloseTags: true,
+                autoCloseBrackets: true,
+                height: "auto",
+                styleActiveLine: true,
+
+                extraKeys: {
+                    "Tab": "indentMore",
+                    "Shift-Tab": "indentLess",
+                }
+            });
+            restoreScrollPosition("'.$resource.'");
+        </script>';
+    }
+
+    $result .= &Apache::loncommon::end_page();
+    &Apache::lonxml::add_messages(\$result);
     $request->print($result);
-  }
-  return '';
+    }
+    return '';
 }
 
+#
+#    Render the page in whatever target desired.
+#
 sub renderpage {
-  my ($request,$file) = @_;
+    my ($request,$file,$targets,$return_string,$donebuttonmsg,$viewasuser,$symb) = @_;
 
-  my (@targets) = &get_target();
-  &Apache::lonxml::debug("Running targets ".join(':',@targets));
-  foreach my $target (@targets) {
-    #my $t0 = [&gettimeofday()];
-    my $problem=&Apache::lonnet::getfile($file);
-    if ($problem eq -1) {
-      &Apache::lonxml::error("<b> Unable to find <i>$file</i></b>");
-      $problem='';
-    }
+    my @targets = @{$targets || [&get_target()]};
+    &Apache::lonhomework::showhashsubset(\%env,'form.');
+    &Apache::lonxml::debug("Running targets ".join(':',@targets));
+
+    my $overall_result;
+    foreach my $target (@targets) {
+	# FIXME need to do something intelligent when a problem goes
+        # from viewable to not viewable due to map conditions
+	#&setuppermissions();
+	#if (   $Apache::lonhomework::browse ne '2'
+	#    && $Apache::lonhomework::browse ne 'F' ) {
+	#    $request->print(" You most likely shouldn't see me.");
+	#}
+	#my $t0 = [&gettimeofday()];
+	my $output=1;
+	if ($target eq 'no_output_web') {
+	    $target = 'web'; $output=0;
+	}
+	my $problem=&Apache::lonnet::getfile($file);
+	my $result;
+	if ($problem eq -1) {
+	    $problem='';
+	    my $filename=(split('/',$file))[-1];
+	    my $error =
+		'<p class="LC_error">'
+               .&mt('Unable to find [_1]',
+			   '<span class="LC_filename">'.$filename.'</span>')
+		."</p>";
+	    $result.=
+		&Apache::loncommon::simple_error_page($request,'Not available',
+						      $error,{'no_auto_mt_msg' => 1});
+	    return;
+	}
 
-    my %mystyle;
-    my $result = '';
-    if ($target eq 'analyze') { %Apache::lonhomework::analyze=(); }
-    if ($target eq 'answer') { &showhash(%Apache::lonhomework::history); }
-    if ($target eq 'web') {&Apache::lonhomework::showhashsubset(\%ENV,'^form');}
-
-    &Apache::lonxml::debug("Should be parsing now");
-    $result = &Apache::lonxml::xmlparse($request, $target, $problem,
-			&setup_vars($target),%mystyle);
-    undef($Apache::lonhomework::parsing_a_problem);
-    #$request->print("Result follows:");
-    if ($target eq 'modified') {
-      &handle_save_or_undo($request,\$problem,\$result);
+	my %mystyle;
+	if ($target eq 'analyze') { %Apache::lonhomework::analyze=(); }
+	if ($target eq 'answer') { &showhash(%Apache::lonhomework::history); }
+	if ($target eq 'web') {&Apache::lonhomework::showhashsubset(\%env,'^form');}
+
+        if (($target eq 'web') && ($viewasuser ne '') && ($symb ne '')) {
+            $env{'request.user_in_effect'} = $viewasuser;
+        }
+
+	&Apache::lonxml::debug("Should be parsing now");
+	$result .= &Apache::lonxml::xmlparse($request, $target, $problem,
+					     &setup_vars($target),%mystyle);
+	&finished_parsing();
+	if (!$output) { $result = ''; }
+	#$request->print("Result follows:");
+	if ($target eq 'modified') {
+	    &handle_save_or_undo($request,\$problem,\$result);
+	} else {
+	    if ($target eq 'analyze') {
+		$result=&Apache::lonnet::hashref2str(\%Apache::lonhomework::analyze);
+		undef(%Apache::lonhomework::analyze);
+	    } elsif ($target eq 'web') {
+                if ($donebuttonmsg) {
+                    $result =~ s{</body>}{};
+                    $result.= &Apache::loncommon::confirmwrapper(&Apache::lonhtmlcommon::confirm_success($donebuttonmsg,1))."\n</body>";
+                }
+            }
+	    #my $td=&tv_interval($t0);
+	    #if ( $Apache::lonxml::debug) {
+	    #$result =~ s:</body>::;
+	    #$result.="<br />Spent $td seconds processing target $target\n</body>";
+	    #}
+#	    $request->print($result);
+	    $overall_result.=$result;
+            if (($target eq 'web') && ($viewasuser ne '') && ($symb ne '')) {
+                my ($vuname,$vudom) = split(/:/,$viewasuser);
+                $overall_result .= &Apache::grades::view_as_user($symb,$vuname,$vudom).
+                                   '</body></html>';
+            }
+#	    $request->rflush();
+	}
+        if (($target eq 'web') && ($viewasuser ne '') && ($symb ne '')) {
+            undef($env{'request.user_in_effect'});
+        }
+	#$request->print(":Result ends");
+	#my $td=&tv_interval($t0);
+    }
+    if (!$return_string) {
+	&Apache::lonxml::add_messages(\$overall_result);
+	$request->print($overall_result);   
+	$request->rflush();
     } else {
-      if ($target eq 'analyze') {
-	$result=&Apache::lonnet::hashref2str(\%Apache::lonhomework::analyze);
-	undef(%Apache::lonhomework::analyze);
-      }
-      #my $td=&tv_interval($t0);
-      #if ( $Apache::lonxml::debug) {
-	#$result =~ s:</body>::;
-	#$result.="<br />Spent $td seconds processing target $target\n</body>";
-      #}
-      $request->print($result);
-      $request->rflush();
+	return $overall_result;
     }
-    #$request->print(":Result ends");
-    #my $td=&tv_interval($t0);
-  }
 }
 
-# with no arg it returns a HTML <option> list of the template titles
-# with one arg it returns the filename associated with the arg passed
-sub get_template_list {
-  my ($namewanted,$extension) = @_;
-  my $result;
-  my @allnames;
-  &Apache::lonxml::debug("Looking for :$extension:");
-  foreach my $file (</home/httpd/html/res/adm/includes/templates/*.$extension>) {
-    my $name=&Apache::lonnet::metadata($file,'title');
-    if ($namewanted && ($name eq $namewanted)) {
-      $result=$file;
-      last;
-    } else {
-	if ($name) { push (@allnames, $name); }
+sub finished_parsing {
+    undef($Apache::lonhomework::parsing_a_problem);
+    undef($Apache::lonhomework::parsing_a_task);
+}
+
+# function extracted from get_template_html
+# returns "key" -> list
+# key: path of template
+# value 1: title
+# value 2: category
+# value 3: name of help topic ???
+sub get_template_list{
+    my ($extension) = @_;
+
+    my @files = glob($Apache::lonnet::perlvar{'lonIncludes'}.
+                     '/templates/*.'.$extension);
+    @files = map {[$_,&mt(&Apache::lonnet::metadata($_, 'title')),
+                      (&Apache::lonnet::metadata($_, 'category')?&mt(&Apache::lonnet::metadata($_, 'category')):&mt('Miscellaneous')),
+                      &mt(&Apache::lonnet::metadata($_, 'help'))]} (@files);
+    @files = sort {$a->[2].$a->[1] cmp $b->[2].$b->[1]} (@files);
+    return @files;
+}
+
+sub get_template_html {
+    my ($extension) = @_;
+    my $result;
+    my @allnames;
+    &Apache::lonxml::debug("Looking for :$extension:");
+    my $glob_extension  = $extension;
+    if ($extension eq 'survey' || $extension eq 'exam') {
+	$glob_extension = 'problem';
+    }
+    my @files = &get_template_list($extension);
+    my ($midpoint,$seconddiv,$numfiles);
+    my @noexamplelink = ('blank.problem','blank.library','script.library');
+    $numfiles = 0;
+    foreach my $file (@files) {
+        next if ($file->[1] !~ /\S/);
+        $numfiles ++;
+    }
+    if ($numfiles > 0) {
+        $result = '<div class="LC_left_float">';
+        $midpoint = int($numfiles/2);
+        if ($numfiles%2) {
+            $midpoint ++;
+        }
+    }
+    my $count = 0;
+    my $currentcategory='';
+    my $first = 1;
+    my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
+    foreach my $file (@files) {
+	next if ($file->[1] !~ /\S/);
+        if ($file->[2] ne $currentcategory) {
+           $currentcategory=$file->[2];
+           if ((!$seconddiv) && ($count >= $midpoint)) {
+               $result .= '</div></div>'."\n".'<div class="LC_left_float">'."\n";
+               $seconddiv = 1;
+           } elsif (!$first) {
+               $result.='</div>'."\n";
+           } else {
+               $first = 0;
+           }
+           $result.= '<div class="LC_Box">'."\n"
+                    .'<h3 class="LC_hcell">'.$currentcategory.'</h3>'."\n";
+           $count++;
+        }
+	$result .=
+	    '<label><input type="radio" name="template" value="'.$file->[0].'" />'.
+	    $file->[1].'</label>';
+        if ($file->[3]) {
+           $result.=&Apache::loncommon::help_open_topic($file->[3]);
+        }
+        # Provide example link
+        my $filename=$file->[0];
+        $filename=~s{^\Q$londocroot\E}{};
+        if (!(grep($filename =~ /\Q$_\E$/,@noexamplelink))) {
+            $result .= ' <span class="LC_fontsize_small">'
+                      .&Apache::loncommon::modal_link(
+                           $filename.'?inhibitmenu=yes',&mt('Example'),600,420,'sample')
+                      .'</span>';
+        }
+        $result .= '<br />'."\n";
+        $count ++;
+    }
+    if ($numfiles > 0) {
+        $result .= '</div></div>'."\n".'<div class="LC_clear_float_footer"></div>'."\n";
     }
-  }
-  if (@allnames && !$result) {
-    $result="<option>Select a $extension template</option>\n<option>".
-	join('</option><option>',sort(@allnames)).'</option>';
-  }
-  return $result;
+    return $result;
 }
 
 sub newproblem {
     my ($request) = @_;
-    my $extension=$request->uri;
-    $extension=~s:^.*\.([\w]+)$:$1:;
+
+    if ($env{'form.mode'} eq 'blank'){
+        my $dest = &Apache::lonnet::filelocation("",$request->uri);
+        my $templatefilename =
+            $request->dir_config('lonIncludes').'/templates/blank.problem';
+        &File::Copy::copy($templatefilename,$dest);
+        &renderpage($request,$dest);
+        return;
+    }
+    my $errormsg;
+    if ($env{'form.template'}) {
+        my $file;
+        my ($extension) = ($env{'form.template'} =~ /\.(\w+)$/);
+        if ($extension) {
+            my @files = &get_template_list($extension);
+            foreach my $poss (@files) {
+                if (ref($poss) eq 'ARRAY') {
+                    if ($env{'form.template'} eq $poss->[0]) {
+                        $file = $env{'form.template'};
+                        last;
+                    }
+                }
+            }
+            if ($file) {
+	        my $dest = &Apache::lonnet::filelocation("",$request->uri);
+	        &File::Copy::copy($file,$dest);
+	        &renderpage($request,$dest);
+	        return;
+            } else {
+                $errormsg = '<p class="LC_error">'.&mt('Invalid template file.').'</p>';
+            }
+        } else {
+            $errormsg = '<p class="LC_error">'.&mt('Invalid template file; template needs to be a .problem, .library, or .task file.').'</p>';
+        }
+    }
+
+    my ($extension) = ($request->uri =~ m/\.(\w+)$/);
     &Apache::lonxml::debug("Looking for :$extension:");
-    my $templatelist=&get_template_list('',$extension);
-    if ($ENV{'form.template'} &&
-	$ENV{'form.template'} ne "Select a $extension template") {
-	use File::Copy;
-	my $file = &get_template_list($ENV{'form.template'},$extension);
-	my $dest = &Apache::lonnet::filelocation("",$request->uri);
-	copy($file,$dest);
-	&renderpage($request,$dest);
-    } elsif($ENV{'form.newfile'} && !$templatelist) {
-	# I don't like hard-coded filenames but for now, this will work.
-	use File::Copy;
+    my $templatelist=&get_template_html($extension);
+    if ($env{'form.newfile'} && !$templatelist) {
+	# no templates found
 	my $templatefilename =
-	    $request->dir_config('lonIncludes').'/templates/blank.problem';
+	    $request->dir_config('lonIncludes').'/templates/blank.'.$extension;
 	&Apache::lonxml::debug("$templatefilename");
 	my $dest = &Apache::lonnet::filelocation("",$request->uri);
-	copy($templatefilename,$dest);
+	&File::Copy::copy($templatefilename,$dest);
 	&renderpage($request,$dest);
     } else {
-	my $url=$request->uri;
+	my $url=&HTML::Entities::encode($request->uri,'<>&"');
 	my $dest = &Apache::lonnet::filelocation("",$request->uri);
-	my $errormsg;
-	if ($ENV{'form.newfile'}) {
-	    $errormsg='<p><font color="red">You did not select a template.</font></p>'."\n";
-	}
 	my $instructions;
-	if ($templatelist) { $instructions=", select a template from the pull-down menu below.<br />Then";}
-	$request->print(<<ENDNEWPROBLEM);
-<body bgcolor="#FFFFFF">
-<h1>Creating a new $extension resource</h1>
+        my $text = 'Authoring Space';
+        my $href = &Apache::loncommon::authorspace($request->uri);
+        if ($env{'request.course.id'}) {
+            my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+            my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+            if ($href eq "/priv/$cdom/$cnum/") {
+                $text = 'Course Authoring Space';
+            }
+        }
+        my $brcrum = [{'href' => $href,
+                       'text' => $text},
+                      {'href' => '',
+                       'text' => "Create New $extension"}];
+	my $start_page = 
+            &Apache::loncommon::start_page("Create New $extension",
+                                           undef,
+                                           {'bread_crumbs' => $brcrum,});
+	$request->print(
+        $start_page
+       .&Apache::loncommon::head_subbox(
+                &Apache::loncommon::CSTR_pageheader())
+       .'<h1>'.&mt("Creating a new $extension resource.")."</h1>
 $errormsg
-The requested file <tt>$url</tt> currently does not exist.
-<p>
-<b>To create a new $extension$instructions click on the "Create $extension" button.</b>
-</p>
-<p><form action="$url" method="POST">
-ENDNEWPROBLEM
+".&mt("The requested file [_1] currently does not exist.",
+      '<span class="LC_filename">'.$url.'</span>').'
+<p class="LC_info">
+'.&mt("To create a new $extension, select a template from the".
+      " list below. Then click on the \"Create $extension\" button.").'
+</p><div><form action="'.$url.'" method="post">');
+
 	if (defined($templatelist)) {
-	    $request->print("<select name=\"template\">$templatelist</select>");
+	    $request->print($templatelist);
+	}
+	$request->print('<br /><input type="submit" name="newfile" value="'.
+			&mt("Create $extension").'" />');
+	$request->print('</form></div>'.&Apache::loncommon::end_page());
+    }
+    return;
+}
+
+sub update_construct_style {
+    if ($env{'request.state'} eq "construct"
+	&& $env{'form.problemmode'} eq 'view' 
+	&&  defined($env{'form.submitted'})
+	&& !defined($env{'form.resetdata'})
+	&& !defined($env{'form.newrandomization'})) {
+	if ((!$env{'form.style_file'} && $env{'construct.style'})
+	    ||$env{'form.clear_style_file'}) {
+	    &Apache::lonnet::delenv('construct.style');
+	} elsif ($env{'form.style_file'} 
+	    && $env{'construct.style'} ne $env{'form.style_file'}) {
+	    &Apache::lonnet::appenv({'construct.style' => 
+				        $env{'form.style_file'}});
 	}
-	$request->print("<br /><input type=\"submit\" name=\"newfile\" value=\"Create $extension\" />");
-	$request->print("</form></p></body>");
     }
-    return '';
 }
 
-sub view_or_edit_menu {
-  my ($request) = @_;
-  my $url=$request->uri;
-  $request->print(<<EDITMENU);
-<body bgcolor="#FFFFFF">
-<form action="$url" method="POST">
-Would you like to <input type="submit" name="problemmode" value="View"> or
-<input type="submit" name="problemmode" value="Edit"> the problem.
-</form>
-</body>
-EDITMENU
+#
+# Sets interval for current user so time left will be zero, either for the entire folder
+# containing the current resource, or just the resource, depending on value of first item
+# in interval array retrieved from EXT("resource.0.interval");
+#
+sub zero_timer {
+    my ($symb) = @_;
+    my ($hastimeleft,$first_access,$now);
+    my @interval=&Apache::lonnet::EXT("resource.0.interval",$symb);
+    if (@interval > 1) {
+        if ($interval[1] eq 'course') {
+            return ('fail',&mt('Ending of timed events not supported for intervals set course-wide'));
+        } else {
+            my $now = time;
+            my $first_access=&Apache::lonnet::get_first_access($interval[1],$symb);
+            if ($first_access > 0) {
+                my ($timelimit,$donesuffix) = split(/_/,$interval[0],2);
+                if ($donesuffix =~ /^done(?:|\:[^\:]+\:)(.*)$/) {
+                    my ($dummy,$proctor,$secret) = split(/_/,$1);
+                    if (($proctor) && ($secret ne '')) {
+                        my $key = $env{'form.LC_interval_done_proctorpass'};
+                        $key =~ s/^\s+//;
+                        $key =~ s/\s+$//;
+                        if ($env{'form.LC_interval_done_proctorpass'} ne $secret) {
+                            return ('fail',
+                                   &mt('Incorrect key entered by proctor'));
+                        }
+                    }
+                    if ($first_access+$timelimit > $now) {
+                        my $done_time = $now - $first_access;
+                        my $snum = 1;
+                        if ($interval[1] eq 'map') {
+                            $snum = 2;
+                        }
+                        my $result =
+                            &Apache::lonparmset::storeparm_by_symb_inner($symb,'0_interval',
+                                                                         $snum,$done_time,
+                                                                         'date_interval',
+                                                                         $env{'user.name'},
+                                                                         $env{'user.domain'});
+                        if ($result eq '') {
+                            # Record action in "User Notes"
+                            &Apache::lonmsg::store_instructor_comment(
+                                'Pressed Done button for symb:<br />'.$symb,
+                                $env{'user.name'}, $env{'user.domain'});
+                            return ('ok');
+                        } else {
+                            return ('fail',&mt('Error ending timed event: [_1]',$result));
+                        }
+                    } else {
+                        return ('fail',&mt('Timed event already ended'));
+                    }
+                } else {
+                    return ('fail',&mt('Timed event can not be ended before the time limit'));
+                }
+            } else {
+                return ('fail',&mt('Timer not yet started for this timed event'));
+            }
+        }
+    } else {
+        return ('fail',&mt('No timer in use'));
+    }
+    return();
 }
 
 sub handler {
-  #my $t0 = [&gettimeofday()];
-  my $request=$_[0];
+    #my $t0 = [&gettimeofday()];
+    my $request=$_[0];
 
-  $Apache::lonxml::debug=$ENV{'user.debug'};
+    $Apache::lonxml::request=$request;
+    $Apache::lonxml::debug=$env{'user.debug'};
+    $env{'request.uri'}=$request->uri;
+    &setuppermissions();
+
+# -------------------------------------- Flag and buffer for registered cleanup
+    $registered_cleanup=0;
+    undef(@Apache::lonhomework::ltipassback);
+
+    my $file=&Apache::lonnet::filelocation("",$request->uri);
+
+    #check if we know where we are
+    if ($env{'request.course.fn'} && !&Apache::lonnet::symbread('','',1,1)) {
+	# if we are browsing we might not be able to know where we are
+	if ($Apache::lonhomework::browse ne 'F' &&
+	    $env{'request.state'} ne "construct") {
+	    #should know where we are, so ask
+	    &unset_permissions();
+	    $request->internal_redirect('/adm/ambiguous');
+	    return OK;
+	}
+    }
+    if (&setupheader($request)) {
+	&unset_permissions();
+	return OK;
+    }
+
+    &Apache::lonxml::debug("Permissions:$Apache::lonhomework::browse:$Apache::lonhomework::viewgrades:$Apache::lonhomework::modifygrades:$Apache::lonhomework::queuegrade");
+    &Apache::lonxml::debug("Problem Mode ".$env{'form.problemmode'});
+    my ($symb) = &Apache::lonnet::whichuser();
+    &Apache::lonxml::debug('symb is '.$symb);
+    if ($env{'request.state'} eq "construct") {
+	if ( -e $file ) {
+	    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
+						    ['problemmode']);
+	    if (!(defined $env{'form.problemmode'})) {
+		#first visit to problem in construction space
+		$env{'form.problemmode'}= 'view';
+		&renderpage($request,$file);
+	    } elsif (($env{'form.problemmode'} eq 'editxml') || 
+                     ($env{'form.problemmode'} eq 'saveeditxml') ||
+                     ($env{'form.problemmode'} eq 'saveviewxml') ||
+                     ($env{'form.problemmode'} eq 'undoxml')) {
+                my %editors = &Apache::loncommon::permitted_editors();
+                if (($editors{'xml'}) || ($env{'form.problemmode'} eq 'saveviewxml') || ($env{'form.problemmode'} eq 'undoxml')) {
+		    &editxmlmode($request,$file);
+                } else {
+                    &update_construct_style();
+                    &renderpage($request,$file);
+                }
+	    } elsif ($env{'form.problemmode'} eq 'calcanswers') {
+		&analyze($request,$file);
+	    } else {
+		&update_construct_style();
+		&renderpage($request,$file);
+	    }
+	} else {
+		&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
+						    ['mode']);
+	    # requested file doesn't exist in contruction space
+	    &newproblem($request);
+	}
+    } else {
+        # Set the event timer to zero if the "done button" was clicked.  The button is
+        # part of the doneButton form created in lonmenu.pm
+        my ($donebuttonresult,$donemsg,$viewasuser);
+        if ($symb && $env{'form.LC_interval_done'} eq 'true') {  
+            ($donebuttonresult,$donemsg) = &zero_timer($symb);
+            undef($env{'form.LC_interval_done'});
+            undef($env{'form.LC_interval_done_proctorpass'});
+        }
+        if (($env{'form.LC_viewas'} ne '') && $symb && $env{'request.course.id'} &&
+            ($Apache::lonhomework::viewgrades || $Apache::lonhomework::modifygrades)) {
+            if ($env{'form.LC_viewas'} =~ /^($match_username):($match_domain)$/) {
+                my ($possuname,$possudom) = ($1,$2);
+                my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+                my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+                my ($canview,$posssec);
+                if ($env{'request.course.sec'} ne '') {
+                    if ($Apache::lonhomework::modifygradessec eq $env{'request.course.sec'}) {
+                        $canview = 'section';
+                        $posssec = $env{'request.course.sec'};
+                    } elsif ($Apache::lonhomework::viewgradessec eq $env{'request.course.sec'}) {
+                        $canview = 'section';
+                        $posssec = $env{'request.course.sec'};
+                    }
+                }
+                my $crstype = &Apache::loncommon::course_type();
+                if (&Apache::loncourseuser::is_course_user($possudom,$possuname,$cdom,$cnum,
+                                                           $canview,$crstype,$posssec)) {
+                    $viewasuser = $possuname.':'.$possudom;
+                }
+            }
+            undef($env{'form.LC_viewas'});
+        }
+	# just render the page normally outside of construction space
+	&Apache::lonxml::debug("not construct");
+	&renderpage($request,$file,undef,undef,$donemsg,$viewasuser,$symb);
+        if (@Apache::lonhomework::ltipassback) {
+            unless ($registered_cleanup) {
+                my $handlers = $request->get_handlers('PerlCleanupHandler');
+                $request->set_handlers('PerlCleanupHandler' =>
+                                       [\&do_ltipassback,@{$handlers}]);
+                $registered_cleanup=1;
+            }
+        }
+    }
+    #my $td=&tv_interval($t0);
+    #&Apache::lonxml::debug("Spent $td seconds processing");
+    # always turn off debug messages
+    $Apache::lonxml::debug=0;
+    &unset_permissions();
+    return OK;
 
-  if (&setupheader($request)) { return OK; }
-  $ENV{'request.uri'}=$request->uri;
+}
 
-  #setup permissions
-  $Apache::lonhomework::browse= &Apache::lonnet::allowed('bre',$ENV{'request.filename'});
-  $Apache::lonhomework::viewgrades=&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'});
-  &Apache::lonxml::debug("Permissions:$Apache::lonhomework::browse:$Apache::lonhomework::viewgrades:");
-  # some times multiple problemmodes are submitted, need to select
-  # the last one
-  &Apache::lonxml::debug("Problem Mode ".$ENV{'form.problemmode'});
-  if ( defined($ENV{'form.problemmode'}) &&
-       ref($ENV{'form.problemmode'}) ) {
-    &Apache::lonxml::debug("Problem Mode ".join(",",@$ENV{'form.problemmode'}));
-    my $mode=$ENV{'form.problemmode'}->[-1];
-    undef $ENV{'form.problemmode'};
-    $ENV{'form.problemmode'}=$mode;
-  }
-  &Apache::lonxml::debug("Problem Mode ".$ENV{'form.problemmode'});
-  my $file=&Apache::lonnet::filelocation("",$request->uri);
-
-  #check if we know where we are
-  if ($ENV{'request.course.fn'} && !&Apache::lonnet::symbread()) { 
-    # if we are browsing we might not be able to know where we are
-    if ($Apache::lonhomework::browse ne 'F') {
-      #should know where we are, so ask
-	if ( Apache::exists_config_define("MODPERL2") ) {
-	    &Apache::lonnet::cleanenv();
-	}
-	$request->internal_redirect('/adm/ambiguous'); return;
-    }
-  }
-
-  my ($symb) = &Apache::lonxml::whichuser();
-  &Apache::lonxml::debug('symb is '.$symb);
-  if ($ENV{'request.state'} eq "construct" || $symb eq '') {
-      if ($ENV{'form.resetdata'} eq 'Reset Submissions' ||
-	  $ENV{'form.resetdata'} eq 'New Problem Variation' ||
-          $ENV{'form.newrandomization'} eq 'New Randomization') {
-	  my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser();
-	  &Apache::lonnet::tmpreset($symb,'',$domain,$name);
-&Apache::lonxml::debug("Attempt reset");
-      }
-  }
-  if ($ENV{'request.state'} eq "construct") {
-    if ( -e $file ) {
-      &Apache::loncommon::get_unprocessed_cgi
-                          ($ENV{'QUERY_STRING'},['problemmode']);
-      if (!(defined $ENV{'form.problemmode'})) {
-	#first visit to problem in construction space
-	#&view_or_edit_menu($request);
-	$ENV{'form.problemmode'}='View';
-	&renderpage($request,$file);
-      } elsif ($ENV{'form.problemmode'} eq 'EditXML') {
-	&editxmlmode($request,$file);
-      } elsif ($ENV{'form.problemmode'} eq 'Calculate answers') {
-	&analyze($request,$file);
-      } else {
-	&renderpage($request,$file);
-      }
-    } else {
-      # requested file doesn't exist in contruction space
-      &newproblem($request);
+sub template_dropdown_datastructure {
+    # gathering the all templates and their path, title, category and help topic
+    my @templates = get_template_list('problem');
+    # template category => title
+    my %tmplthash = ();
+    # template title => path
+    my %tmpltcontent = ();
+	
+    foreach my $template (@templates){
+        # put in hash if the template is not empty
+        unless ($template->[1] eq ''){
+            push(@{$tmplthash{$template->[2]}}, $template->[1]);
+            push(@{$tmpltcontent{$template->[1]}},$template->[0]);
+        }
+    }
+
+	my $catList = [];
+    foreach my $cat (sort keys %tmplthash) {
+		my $catItems = [];
+        foreach my $title (sort @{$tmplthash{$cat}}) {
+            my $path = $tmpltcontent{$title}->[0];
+            my $code;
+            open(FH, "<$path");
+            while(<FH>){
+                $code.= $_ unless $_ =~ /(<problem>)|(<\/problem>)/;
+            }
+            close(FH);
+
+			if ($code ne '') {				
+                my $href = 'javascript:insertText(\'' . &convert_for_js(&HTML::Entities::encode($code,'<>&"')) . '\')';
+				my $currItem = [$href, $title, undef];
+				push @{$catItems}, $currItem;
+			}
+        }
+		push @{$catList}, [$catItems, $cat, undef];
     }
-  } else {
-    # just render the page normally outside of construction space
-    &Apache::lonxml::debug("not construct");
-    &renderpage($request,$file);
-  }
-  #my $td=&tv_interval($t0);
-  #&Apache::lonxml::debug("Spent $td seconds processing");
-  # &Apache::lonhomework::send_footer($request);
-  # always turn off debug messages
-  $Apache::lonxml::debug=0;
-  return OK;
 
+    return $catList;
+}
+
+sub responseblock_dropdown_datastructure {
+	
+	my $mathCat = [
+		[
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_formularesponse())) . "\')", &mt("Formula Response"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_functionplotresponse())) . "\')", &mt("Function Plot Response"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_mathresponse())) . "\')", &mt("Math Response"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_numericalresponse())) . "\')", &mt("Numerical Response"), undef]
+		], 
+		&mt("Math"), 
+		undef
+	];
+
+	my $miscCat = [		
+		[
+            ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_imageresponse())) . "\')", &mt("Click on Image"), undef],
+            ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_customresponse())) . "\')", &mt("Custom Response"), undef],
+            ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_externalresponse())) . "\')", &mt("External Response"), undef],
+            ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_matchresponse())) . "\')", &mt("Match Two Lists"), undef],
+            ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_radiobuttonresponse())) . "\')", &mt("One out of N statements"), undef],
+            ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_optionresponse())) . "\')", &mt("Select from Options"), undef], 
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_rankresponse())) . "\')", &mt("Rank Values"), undef]
+		],
+		&mt("Miscellaneous"),
+		undef
+	];
+
+	my $chemCat = [
+		[
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_reactionresponse())) . "\')", &mt("Chemical Reaction"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_organicresponse())) . "\')", &mt("Organic Chemical Structure"), undef]
+		],
+		&mt("Chemistry"),
+		undef
+	];
+
+	my $textCat = [
+		[
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_stringresponse())) . "\')", &mt("String Response"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_essayresponse())) . "\')", &mt("Essay"), undef]
+		],
+		&mt("Text"),
+		undef
+	];
+
+    return [$mathCat, $miscCat, $chemCat, $textCat];
+}
+
+
+sub conditional_scripting_datastructure {
+# TODO: corresponding routines should be used for the javascript:insertText parts
+# instead of the placeholder routine default_xml_tag with the tags
+# e.g. &default_xml_tag("postanswerdate") should be replaced with a routine which
+# returns the corresponding content for this case
+
+#TODO translated is currently temporarily here, another solution should be found where the
+# needed string can be retrieved
+
+	my $translatedTag = '
+<translated>
+    <lang which="en"></lang>
+    <lang which="default"></lang>
+</translated>';
+    return [
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode($translatedTag)) . "\')", &mt("Translated Block"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("block"))) . "\')", &mt("Conditional Block"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("postanswerdate"))) . "\')", &mt("After Answer Date Block"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("preduedate"))) . "\')", &mt("Before Due Date Block"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("solved"))) . "\')", &mt("Block For After Solved"), undef],
+			["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("notsolved"))) . "\')", &mt("Block For When Not Solved"), undef]
+        ];
+}
+
+sub misc_datastructure {
+    return [
+        ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_img())) . "\')", &mt("Image"), undef],
+        ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::lonplot::insert_gnuplot())) . "\')", &mt("GNU Plot"), undef],
+        ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_organicstructure())) . "\')", &mt("Organic Structure"), undef],
+        ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::edit::insert_script())) . "\')", &mt("Script Block"), undef],
+        ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("allow"))) . "\')", &mt("File Dependencies"), undef],
+        ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("import"))) . "\')", &mt("Import a File"), undef],
+        ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&Apache::londefdef::insert_meta())) . "\')", &mt("Custom Metadata"), undef],
+        ["javascript:insertText(\'" . &convert_for_js(&HTML::Entities::encode(&default_xml_tag("part"))) . "\')", &mt("Problem Part"), undef]
+    ];
+}
+
+# helper routine for the datastructure building subroutines
+sub default_xml_tag {
+	my ($tag) = @_;
+	return "\n<$tag></$tag>";
+}
+
+
+sub helpmenu_datastructure {
+
+	# filename, title, width, height
+	my $helpers = [
+		['Problem_LON-CAPA_Functions.hlp', &mt('Script Functions'), 800, 600],
+		['Greek_Symbols.hlp', &mt('Greek Symbols'), 500, 600],
+ 		['Other_Symbols.hlp', &mt('Other Symbols'), 500, 600],
+		['Authoring_Output_Tags.hlp', &mt('Output Tags'), 800, 600],
+		['Authoring_Multilingual_Problems.hlp', 
+			&mt('How to create problems in different languages'), 800, 600],
+		['loncapa.html', &mt('Language reference'), 800, 600],
+	];
+
+	my $help_structure = [];
+
+	foreach my $count (0..(scalar(@{$helpers})-1)) {
+		my $filename = $helpers->[$count]->[0];
+		my $title = $helpers->[$count]->[1];
+		my $width = $helpers->[$count]->[2];
+                my $height = $helpers->[$count]->[3];
+                if ($width eq '') {
+                    $width = 500;
+                }
+                if ($height eq '') {
+                    $height = 600;
+                }
+		my $href = &HTML::Entities::encode("javascript:openMyModal('/adm/help/$filename',$width,$height,'yes');");
+		push @{$help_structure}, [$href, $title, undef];
+	}
+
+	return $help_structure;
+}
+
+# we need substitution to not break javascript code
+sub convert_for_js {
+    my $return = shift;
+        $return =~ s|script|ESCAPEDSCRIPT|g;
+        $return =~ s|\\|\\\\|g;
+        $return =~ s|\n|\\r\\n|g;
+        $return =~ s|'|\\'|g;
+		$return =~ s|&#39;|\\&#39;|g;
+    return $return;
+}
+
+sub do_ltipassback {
+    if (@Apache::lonhomework::ltipassback) {
+        my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
+        my $ip = &Apache::lonnet::get_host_ip($lonhost);
+        foreach my $item (@Apache::lonhomework::ltipassback) {
+            &Apache::lonhomework::run_passback($item,$lonhost,$ip);
+        }
+        undef(@Apache::lonhomework::ltipassback);
+    }
+    return OK;
+}
+
+sub run_passback {
+    my ($item,$lonhost,$ip) = @_;
+    if (ref($item) eq 'HASH') {
+        if ((ref($item->{'lti'}) eq 'HASH') && ($item->{'cid'} =~ /^($match_domain)_($match_courseid)$/)) {
+            my ($cdom,$cnum) = ($1,$2);
+            my $msgformat = $item->{'lti'}->{'passbackformat'};
+            my $sigmethod = 'HMAC-SHA1';
+            my $ltinum = $item->{'ltinum'};
+            my $id = $item->{'pbid'};
+            my $url = $item->{'pburl'};
+            my $type = $item->{'pbtype'};
+            my $pbscope = $item->{'pbscope'};
+            my $map = $item->{'pbmap'};
+            my $symb = $item->{'pbsymb'};
+            my $uname = $item->{'uname'};
+            my $udom = $item->{'udom'};
+            my $uhome = $item->{'uhome'};
+            my $usec = $item->{'usec'};
+            my $keynum = $item->{'lti'}->{'cipher'};
+            my $crsdef = $item->{'crsdef'};
+            my $scoretype = $item->{'format'};
+            my $scope = $item->{'scope'};
+            my $clientip = $item->{'clientip'};
+            my ($total,$possible,%total_by_symb,%possible_by_symb);
+            if ((exists($item->{'total_s'})) && (ref($item->{'total_s'}) eq 'HASH')) {
+                %total_by_symb = %{$item->{'total_s'}};
+                if ($pbscope eq 'resource') {
+                    if (exists($total_by_symb{$symb})) {
+                        $total = $total_by_symb{$symb};
+                    } else {
+                        $total = $item->{'total'};
+                    }
+                }
+            } elsif ($pbscope eq 'resource') {
+                $total = $item->{'total'};
+            }
+            if ((exists($item->{'possible_s'})) && (ref($item->{'possible_s'}) eq 'HASH')) {
+                %possible_by_symb = %{$item->{'possible_s'}};
+                if ($pbscope eq 'resource') {
+                    if (exists($possible_by_symb{$symb})) {
+                        $possible = $possible_by_symb{$symb};
+                    } else {
+                        $possible = $item->{'possible'};
+                    }
+                }
+            } elsif ($pbscope eq 'resource') {
+                $possible = $item->{'possible'};
+            }
+            if (($pbscope eq 'map') || ($pbscope eq 'nonrec')) {
+                if ((keys(%total_by_symb)) && (keys(%possible_by_symb))) {
+                    ($total,$possible) =
+                    &get_lti_score($uname,$udom,$usec,$map,$pbscope,\%total_by_symb,\%possible_by_symb);
+                } else {
+                   ($total,$possible) = &get_lti_score($uname,$udom,$usec,$map,$pbscope);
+                }
+            } elsif ($pbscope eq 'course') {
+                ($total,$possible) = &get_lti_score($uname,$udom,$usec);
+            }
+            $item->{'total'} = $total;
+            $item->{'possible'} = $possible;
+            if (($id ne '') && ($url ne '') && ($possible)) {
+                my ($sent,$score,$code,$result) =
+                    &LONCAPA::ltiutils::send_grade($cdom,$cnum,$crsdef,$type,$ltinum,$keynum,$id,
+                                                   $url,$scoretype,$sigmethod,$msgformat,$total,$possible);
+                $item->{'score'} = $score;
+                my ($linkprotector,$linkuri,$no_passback,$appname);
+                if ($item->{'linkprot'}) {
+                    ($linkprotector,$linkuri) = split(/:/,$item->{'linkprot'});
+                }
+                if ($sent) {
+                    if ($code == 200) {
+                        if ($item->{'linkprot'}) {
+                            my $skey = join("\0",($linkuri,$linkprotector,$scope));
+                            my $namespace = $cdom.'_'.$cnum.'_lp_passback';
+                            my $store = {
+                                          'score' => $score,
+                                          'ip' => $ip,
+                                          'host' => $Apache::lonnet::perlvar{'lonHostID'},
+                                          'protector' => $linkprotector,
+                                          'deeplink' => $linkuri,
+                                          'scope' => $scope,
+                                          'url' => $url,
+                                          'id' => $id,
+                                          'clientip' => $clientip,
+                                          'whodoneit' => $env{'user.name'}.':'.$env{'user.domain'},
+                                        };
+                            my $value='';
+                            foreach my $key (keys(%{$store})) {
+                                $value.=&escape($key).'='.&Apache::lonnet::freeze_escape($store->{$key}).'&';
+                            }
+                            $value=~s/\&$//;
+                            &Apache::lonnet::courselog(&escape($linkuri).':'.$uname.':'.$udom.':EXPORT:'.$value);
+                            &Apache::lonnet::store_userdata({'score' => $score},$skey,$namespace,$udom,$uname);
+                        }
+                    } else {
+                        if ($item->{'linkprot'}) {
+                           $no_passback = "Passback response was $code ($result).";
+                        }
+                    }
+                } else {
+                    if ($item->{'linkprot'}) {
+                        $no_passback = 'No passback of scores.';
+                    }
+                }
+                if ($no_passback) {
+                    if ($item->{'linkprot'}) {
+                        my ($ltinum,$ltitype) = ($linkprotector =~ /^(\d+)(c|d)$/);
+                        if ($ltitype eq 'c') {
+                            my %lti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider');
+                            if (ref($lti{$ltinum}) eq 'HASH') {
+                                $appname = $lti{$ltinum}{'name'};
+                            }
+                        } elsif ($ltitype eq 'd') {
+                            my %lti = &Apache::lonnet::get_domain_lti($cdom,'linkprot');
+                            if (ref($lti{$ltinum}) eq 'HASH') {
+                                $appname = $lti{$ltinum}{'name'};
+                            }
+                        }
+                        $no_passback .= " LTI launcher $linkprotector ($appname) for $linkuri (${cdom}_${cnum})";
+                        &Apache::lonnet::logthis($no_passback." for $uname:$udom");
+                        &Apache::lonnet::log($udom,$uname,$uhome,"$no_passback score=$score total=$total poss=$possible");
+                        if ($item->{'linkprot'}) {
+                            my $pendingkey = &Time::HiRes::time().':'.$uname.':'.$udom.':'.
+                                             "$linkuri\0$linkprotector\0$scope";
+                            &Apache::lonnet::put('linkprot_passback_pending',{$pendingkey => $item},$cdom,$cnum);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return;
+}
+
+sub get_lti_score {
+    my ($uname,$udom,$usec,$mapurl,$pbscope,$totals,$possibles) = @_;
+    my $navmap = Apache::lonnavmaps::navmap->new($uname,$udom,$usec);
+    if (ref($navmap)) {
+        my $iterator;
+        if ($mapurl ne '') {
+            my $map = $navmap->getResourceByUrl($mapurl);
+            my $firstres = $map->map_start();
+            my $finishres = $map->map_finish();
+            my $recursive = 1;
+            if ($pbscope eq 'nonrec') {
+                $recursive = 0;
+            }
+            $iterator = $navmap->getIterator($firstres,$finishres,undef,$recursive);
+        } else {
+            $iterator = $navmap->getIterator(undef,undef,undef,1);
+        }
+        if (ref($iterator)) {
+            my $depth = 1;
+            my $total = 0;
+            my $possible = 0;
+            my (%totals_by_symb,%possibles_by_symb);
+            if (ref($totals) eq 'HASH') {
+                %totals_by_symb = %{$totals};
+            }
+            if (ref($possibles) eq 'HASH') {
+                %possibles_by_symb = %{$possibles};
+            }
+            $iterator->next(); # ignore first BEGIN_MAP
+            my $curRes = $iterator->next();
+            while ( $depth > 0 ) {
+                if ($curRes == $iterator->BEGIN_MAP()) {$depth++;}
+                if ($curRes == $iterator->END_MAP()) { $depth--; }
+                if (ref($curRes) && $curRes->is_gradable() && !$curRes->randomout) {
+                    my $currsymb = $curRes->symb();
+                    if (($currsymb) && (exists($totals_by_symb{$currsymb})) &&
+                        (exists($possibles_by_symb{$currsymb}))) {
+                        $total += $totals_by_symb{$currsymb};
+                        $possible += $possibles_by_symb{$currsymb};
+                    } else {
+                        my $parts = $curRes->parts();
+                        foreach my $part (@{$parts}) {
+                            next if ($curRes->solved($part) eq 'excused');
+                            $total += $curRes->weight($part) * $curRes->awarded($part);
+                            $possible += $curRes->weight($part);
+                        }
+                    }
+                }
+                $curRes = $iterator->next();
+            }
+            if ($total > $possible) {
+                $total = $possible;
+            }
+            return ($total,$possible);
+        }
+    }
+    return;
 }
 
 1;