[LON-CAPA-cvs] cvs: rat / lonuserstate.pm

foxr foxr at source.lon-capa.org
Thu Aug 4 06:57:26 EDT 2011


foxr		Thu Aug  4 10:57:26 2011 EDT

  Modified files:              
    /rat	lonuserstate.pm 
  Log:
  More reverse engineering and commenting of the map load process.
  
  
-------------- next part --------------
Index: rat/lonuserstate.pm
diff -u rat/lonuserstate.pm:1.138 rat/lonuserstate.pm:1.139
--- rat/lonuserstate.pm:1.138	Tue Jul 26 10:40:23 2011
+++ rat/lonuserstate.pm	Thu Aug  4 10:57:26 2011
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Construct and maintain state and binary representation of course for user
 #
-# $Id: lonuserstate.pm,v 1.138 2011/07/26 10:40:23 foxr Exp $
+# $Id: lonuserstate.pm,v 1.139 2011/08/04 10:57:26 foxr Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -70,6 +70,21 @@
                     $uri,$usedversion,$unusedversion).'<br />';
 }
 
+#  Removes the version number from a URI and returns the resulting
+#  URI (e.g. mumbly.version.stuff => mumbly.stuff).
+#
+#   If the URI has not been seen with a versio before the
+#   hash{'version_'.resultingURI} is set to the  version number.
+#   If the URI has been seen and the version does not match and error
+#   is added to the error string.
+#
+# Parameters:
+#   URI potentially with a version.
+# Returns:
+#   URI with the version cut out.
+# See above for side effects.
+#
+
 sub versiontrack {
     my $uri=shift;
     if ($uri=~/\.(\d+)\.\w+$/) {
@@ -218,7 +233,7 @@
 	if ($token->[1] eq 'resource') {
 	    my $resource_id = &parse_resource($token,$lpc,$ispage,$uri);
 	    if (defined $resource_id) {
-		push(@map_ids, $resource_id);
+		push(@map_ids, $resource_id); 
 	    }
 
        # Link
@@ -226,7 +241,7 @@
 	} elsif ($token->[1] eq 'link' && !$randomize) {
 	    &make_link(++$linkpc,$lpc,$token->[2]->{'to'},
 		       $token->[2]->{'from'},
-		       $token->[2]->{'condition'});
+		       $token->[2]->{'condition'}); # note ..condition may be undefined.
 
 	# condition
 
@@ -241,9 +256,17 @@
     if ($randomize) {
 	if (!$env{'request.role.adv'}) {
 	    my $seed;
+
+	    # In the advanced role, the map's random seed
+	    # parameter is used as the basis for computing the
+	    # seed ... if it has been specified:
+
 	    if (defined($randompickseed{$parent_rid})) {
 		$seed = $randompickseed{$parent_rid};
 	    } else {
+
+		# Otherwise the parent's fully encoded symb is used.
+
 		my ($mapid,$resid)=split(/\./,$parent_rid);
 		my $symb=
 		    &Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},
@@ -252,18 +275,26 @@
 		$seed = $symb;
 	    }
 
-	    # Here for sure we need to pass along the username/domain
+	    # TODO: Here for sure we need to pass along the username/domain
 	    # so that we can impersonate users in lonprintout e.g.
 
 	    my $rndseed=&Apache::lonnet::rndseed($seed);
 	    &Apache::lonnet::setup_random_from_rndseed($rndseed);
-	    @map_ids=&Math::Random::random_permutation(@map_ids);
+	    @map_ids=&math::Random::random_permutation(@map_ids); # randomorder.
 	}
+
+
 	my $from = shift(@map_ids);
 	my $from_rid = $lpc.'.'.$from;
 	$hash{'map_start_'.$uri} = $from_rid;
 	$hash{'type_'.$from_rid}='start';
 
+	# Create links to reflect this random ordering.
+	# BUG?  If there are conditions, this invalidates them?  Then again
+	# with randompick there's no gaurentee the resources required for the
+	# conditinos to work will be selected into the map.
+	# so randompick is inconsistent with a map that has conditions?
+
 	while (my $to = shift(@map_ids)) {
 	    &make_link(++$linkpc,$lpc,$to,$from);
 	    my $to_rid =  $lpc.'.'.$to;
@@ -278,8 +309,10 @@
 
     $parser = HTML::TokeParser->new(\$instr);
     $parser->attr_encoded(1);
+
     # last parse out the mapalias params so as to ignore anything
     # refering to non-existant resources
+
     while (my $token = $parser->get_token) {
 	next if ($token->[0] ne 'S');
 	if ($token->[1] eq 'param') {
@@ -305,6 +338,7 @@
 #    $ispage  - True if this resource is encapsulated in a .page (assembled resourcde).
 #    $uri     - URI of the enclosing resource.
 # Returns:
+#   Value of the id attribute of the tag.
 #
 # Note:
 #   The token is an array that contains the following elements:
@@ -325,10 +359,14 @@
 sub parse_resource {
     my ($token,$lpc,$ispage,$uri) = @_;
     
-    # I refuse to coutenance code like this that has 
+    # I refuse to countenance code like this that has 
     # such a dirty side effect (and forcing this sub to be called within a loop).
     #
     #  if ($token->[2]->{'type'} eq 'zombie') { next; }
+    #
+    #  The original code both returns _and_ skips to the next pass of the >caller's<
+    #  loop, that's just dirty.
+    #
 
     # Zombie resources don't produce anything useful.
 
@@ -336,22 +374,38 @@
 	return undef;
     }
 
-    my $rid=$lpc.'.'.$token->[2]->{'id'};
+    my $rid=$lpc.'.'.$token->[2]->{'id'}; # Resource id in hash is levelcounter.id-in-xml.
+
+    # Save the hash element type and title:
 	    
     $hash{'kind_'.$rid}='res';
     $hash{'title_'.$rid}=$token->[2]->{'title'};
+
+    # Get the version free URI for the resource.
+    # If a 'version' attribute was supplied, and this resource's version 
+    # information has not yet been stored, store it.
+    #
+
     my $turi=&versiontrack($token->[2]->{'src'});
     if ($token->[2]->{'version'}) {
 	unless ($hash{'version_'.$turi}) {
 	    $hash{'version_'.$turi}=$1;
 	}
     }
+    # Pull out the title and do entity substitution on &colon
+    # Q: Why no other entity substitutions?
+
     my $title=$token->[2]->{'title'};
     $title=~s/\&colon\;/\:/gs;
-#   my $symb=&Apache::lonnet::encode_symb($uri,
-#					  $token->[2]->{'id'},
-#					  $turi);
-#   &Apache::lonnet::do_cache_new('title',$symb,$title);
+
+
+
+    # I think the point of all this code is to construct a final
+    # URI that apache and its rewrite rules can use to
+    # fetch the resource.   Thi s sonly necessary if the resource
+    # is not a page.  If the resource is a page then it must be
+    # assembled (at fetch time?).
+
     unless ($ispage) {
 	$turi=~/\.(\w+)$/;
 	my $embstyle=&Apache::loncommon::fileembstyle($1);
@@ -378,7 +432,10 @@
 	    }
 	}
     }
-# Store reverse lookup, remove query string
+    # Store reverse lookup, remove query string resource 'ids'_uri => resource id.
+    # If the URI appears more than one time in the sequence, it's resourcde
+    # id's are constructed as a comma spearated list.
+
     my $idsuri=$turi;
     $idsuri=~s/\?.+$//;
     if (defined($hash{'ids_'.$idsuri})) {
@@ -387,17 +444,37 @@
 	$hash{'ids_'.$idsuri}=''.$rid;
     }
     
+
+
     if ($turi=~/\/(syllabus|aboutme|navmaps|smppg|bulletinboard|viewclasslist)$/) {
 	$turi.='?register=1';
     }
     
+
+    # resource id lookup:  'src'_resourc-di  => URI decorated with a query
+    # parameter as above if necessary due to the resource type.
+    
     $hash{'src_'.$rid}=$turi;
+
+    # Mark the external-ness of the resource:
     
     if ($token->[2]->{'external'} eq 'true') {
 	$hash{'ext_'.$rid}='true:';
     } else {
 	$hash{'ext_'.$rid}='false:';
     }
+
+    # If the resource is a start/finish resource set those
+    # entries in the has so that navigation knows where everything starts.
+    # TODO?  If there is a malformed sequence that has no start or no finish
+    # resource, should this be detected and errors thrown?  How would such a 
+    # resource come into being other than being manually constructed by a person
+    # and then uploaded?  Could that happen if an author decided a sequence was almost
+    # right edited it by hand and then reuploaded it to 'fix it' but accidently cut the
+    #  start or finish resources?
+    #
+    #  All resourcess also get a type_id => (start | finish | normal)    hash entr.
+    #
     if ($token->[2]->{'type'}) {
 	$hash{'type_'.$rid}=$token->[2]->{'type'};
 	if ($token->[2]->{'type'} eq 'start') {
@@ -409,6 +486,12 @@
     }  else {
 	$hash{'type_'.$rid}='normal';
     }
+
+    # Sequences end pages are constructed entities.  They require that the 
+    # map that defines _them_ be loaded as well into the hash...with this resourcde
+    # as the base of the nesting.
+    # Resources like that are also marked with is_map_id => 1 entries.
+    #
     
     if (($turi=~/\.sequence$/) ||
 	($turi=~/\.page$/)) {
@@ -418,22 +501,65 @@
     return $token->[2]->{'id'};
 }
 
+#-------------------------------------------------------------------- link
+#  Links define how you are allowed to move from one resource to another.
+#  They are the transition edges in the directed graph that a map is.
+#  This sub takes informatino from a <link> tag and constructs the
+#  navigation bits and pieces of a map.  There is no requirement that the
+#  resources that are linke are already defined, however clearly the map is 
+#  badly broken if they are not _eventually_ defined.
+#
+#  Note that links can be unconditional or conditional.
+#
+#  Parameters:
+#     linkpc   - The link counter for this level of map nesting (this is 
+#                reset to zero by loadmap prior to starting to process
+#                links for map).
+#     lpc      - The map level ocounter (how deeply nested this map is in
+#                the hierarchy of maps that are recursively read in.
+#     to       - resource id (within the XML) of the target of the edge.
+#     from     - resource id (within the XML) of the source of the edge.
+#     condition- id of condition associated with the edge (also within the XML).
+#
+
 sub make_link {
     my ($linkpc,$lpc,$to,$from,$condition) = @_;
     
+    #  Compute fully qualified ids for the link, the 
+    # and from/to by prepending lpc.
+    #
+
     my $linkid=$lpc.'.'.$linkpc;
     my $goesto=$lpc.'.'.$to;
     my $comesfrom=$lpc.'.'.$from;
     my $undercond=0;
 
+
+    # If there is a condition, qualify it with the level counter.
+
     if ($condition) {
 	$undercond=$lpc.'.'.$condition;
     }
 
+    # Links are represnted by:
+    #  goesto_.fuullyqualifedlinkid => fully qualified to
+    #  comesfrom.fullyqualifiedlinkid => fully qualified from
+    #  undercond_.fullyqualifiedlinkid => fully qualified condition id.
+
     $hash{'goesto_'.$linkid}=$goesto;
     $hash{'comesfrom_'.$linkid}=$comesfrom;
     $hash{'undercond_'.$linkid}=$undercond;
 
+    # In addition:
+    #   to_.fully qualified from => comma separated list of 
+    #   link ids with that from.
+    # Similarly:
+    #   from_.fully qualified to => comma separated list of link ids`
+    #                               with that to.
+    #  That allows us given a resource id to know all edges that go to it
+    #  and leave from it.
+    #
+
     if (defined($hash{'to_'.$comesfrom})) {
 	$hash{'to_'.$comesfrom}.=','.$linkid;
     } else {
@@ -447,6 +573,54 @@
 }
 
 # ------------------------------------------------------------------- Condition
+#
+#  Processes <condition> tags, storing sufficient information about them
+#  in the hash so that they can be evaluated and used to conditionalize
+#  what is presented to the student.
+#
+#  these can have the following attributes 
+#
+#    id    = A unique identifier of the condition within the map.
+#
+#    value = Is a perl script-let that, when evaluated in safe space
+#            determines whether or not the condition is true.
+#            Normally this takes the form of a test on an  Apache::lonnet::EXT call
+#            to find the value of variable associated with a resource in the
+#            map identified by a mapalias.
+#            Here's a fragment of XML code that illustrates this:
+#
+#           <param to="5" value="mainproblem" name="parameter_0_mapalias" type="string" />
+#           <resource src="" id="1" type="start" title="Start" />
+#           <resource src="/res/msu/albertel/b_and_c/p1.problem" id="5"  title="p1.problem" />
+#           <condition value="&EXT('user.resource.resource.0.tries','mainproblem')
+#           <2 " id="61" type="stop" />
+#           <link to="5" index="1" from="1" condition="61" />    
+#
+#           In this fragment:
+#             - The param tag establishes an alias to resource id 5 of 'mainproblem'.
+#             - The resource that is the start of the map is identified.
+#             - The resource tag identifies the resource associated with this tag
+#               and gives it the id 5.
+#             - The condition is true if the tries variable associated with mainproblem
+#               is less than 2 (that is the user has had more than 2 tries).
+#               The condition type is a stop condition which inhibits(?) the associated
+#               link if the condition  is false. 
+#             - The link to resource 5 from resource 1 is affected by this condition.    
+#            
+#    type  = Type of the condition. The type determines how the condition affects the
+#            link associated with it and is one of
+#            -  'force'
+#            -  'stop'
+#              anything else including not supplied..which treated as:
+#            - 'normal'.
+#            Presumably maps get created by the resource assembly tool and therefore
+#            illegal type values won't squirm their way into the XML.
+#
+# Side effects:
+#   -  The kind_level-qualified-condition-id hash element is set to 'cond'.
+#   -  The condition text is pushed into the cond array and its element number is
+#      set in the condid_level-qualified-condition-id element of the hash.
+#   - The condition type is colon appneded to the cond array element for this condition.
 sub parse_condition {
     my ($token,$lpc) = @_;
     my $rid=$lpc.'.'.$token->[2]->{'id'};


More information about the LON-CAPA-cvs mailing list