![]() ![]() | ![]() |
Condition number with more than 1 digit bug
1: # The LearningOnline Network with CAPA 2: # Construct and maintain state and binary representation of course for user 3: # 4: # (Server for RAT Maps 5: # 6: # (Edit Handler for RAT Maps 7: # (TeX Content Handler 8: # 9: # 05/29/00,05/30 Gerd Kortemeyer) 10: # 7/1 Gerd Kortemeyer) 11: # 7/1,7/3,7/4,7/7,7/8,7/10 Gerd Kortemeyer) 12: # 13: # 7/15,7/17,7/18,8/1,8/2,8/4,8/5,8/21,8/22,8/23,8/30,9/2,9/4 Gerd Kortemeyer 14: 15: package Apache::lonuserstate; 16: 17: use strict; 18: use Apache::Constants qw(:common :http); 19: use Apache::File; 20: use HTML::TokeParser; 21: use Apache::lonnet(); 22: use GDBM_File; 23: 24: # ---------------------------------------------------- Globals for this package 25: 26: my $pc; # Package counter 27: my %hash; # The big tied hash 28: my @cond; # Array with all of the conditions 29: my $errtext; # variable with all errors 30: 31: # --------------------------------------------------------- Loads map from disk 32: 33: sub loadmap { 34: my $uri=shift; 35: if ($hash{'map_pc_'.$uri}) { return OK; } 36: 37: $pc++; 38: my $lpc=$pc; 39: $hash{'map_pc_'.$uri}=$lpc; 40: $hash{'map_id_'.$lpc}=$uri; 41: 42: my $fn='/home/httpd/html'.$uri; 43: 44: unless (($fn=~/\.course$/) || 45: ($fn=~/\.sequence$/) || 46: ($fn=~/\.page$/)) { 47: $errtext.="Invalid map: $fn\n"; 48: return OK; 49: } 50: 51: unless (-e $fn) { 52: my $returned=Apache::lonnet::repcopy($fn); 53: unless ($returned eq OK) { 54: $errtext.="Could not import: $fn - "; 55: if ($returned eq HTTP_SERVICE_UNAVAILABLE) { 56: $errtext.="Server unavailable\n"; 57: } 58: if ($returned eq HTTP_NOT_FOUND) { 59: $errtext.="File not found\n"; 60: } 61: if ($returned eq FORBIDDEN) { 62: $errtext.="Access forbidden\n"; 63: } 64: return OK; 65: } 66: } 67: 68: if (-e $fn) { 69: my @content; 70: { 71: my $fh=Apache::File->new($fn); 72: @content=<$fh>; 73: } 74: my $instr=join('',@content); 75: my $parser = HTML::TokeParser->new(\$instr); 76: my $token; 77: 78: my $linkpc=0; 79: 80: $fn=~/\.(\w+)$/; 81: 82: $hash{'map_type_'.$lpc}=$1; 83: 84: while ($token = $parser->get_token) { 85: if ($token->[0] eq 'S') { 86: if ($token->[1] eq 'resource') { 87: # -------------------------------------------------------------------- Resource 88: 89: my $rid=$lpc.'.'.$token->[2]->{'id'}; 90: 91: $hash{'kind_'.$rid}='res'; 92: $hash{'title_'.$rid}=$token->[2]->{'title'}; 93: my $turi=$token->[2]->{'src'}; 94: $hash{'src_'.$rid}=$turi; 95: 96: if (defined($hash{'ids_'.$turi})) { 97: $hash{'ids_'.$turi}.=','.$rid; 98: } else { 99: $hash{'ids_'.$turi}=''.$rid; 100: } 101: 102: if ($token->[2]->{'src'}=~/\/\//) { 103: $hash{'ext_'.$rid}='true:'; 104: } else { 105: $hash{'ext_'.$rid}='false:'; 106: } 107: if ($token->[2]->{'type'}) { 108: $hash{'type_'.$rid}=$token->[2]->{'type'}; 109: if ($token->[2]->{'type'} eq 'start') { 110: $hash{'map_start_'.$uri}="$rid"; 111: } 112: if ($token->[2]->{'type'} eq 'finish') { 113: $hash{'map_finish_'.$uri}="$rid"; 114: } 115: } else { 116: $hash{'type_'.$rid}='normal'; 117: } 118: 119: if (($turi=~/\.course$/) || 120: ($turi=~/\.sequence$/) || 121: ($turi=~/\.page$/)) { 122: $hash{'is_map_'.$rid}=1; 123: &loadmap($turi); 124: } 125: 126: } elsif ($token->[1] eq 'condition') { 127: # ------------------------------------------------------------------- Condition 128: 129: my $rid=$lpc.'.'.$token->[2]->{'id'}; 130: 131: $hash{'kind_'.$rid}='cond'; 132: $cond[$#cond+1]=$token->[2]->{'value'}; 133: $hash{'condid_'.$rid}=$#cond; 134: if ($token->[2]->{'type'}) { 135: $cond[$#cond].=':'.$token->[2]->{'type'}; 136: } else { 137: $cond[$#cond].=':normal'; 138: } 139: 140: } elsif ($token->[1] eq 'link') { 141: # ----------------------------------------------------------------------- Links 142: 143: $linkpc++; 144: my $linkid=$lpc.'.'.$linkpc; 145: 146: my $goesto=$lpc.'.'.$token->[2]->{'to'}; 147: my $comesfrom=$lpc.'.'.$token->[2]->{'from'}; 148: my $undercond=0; 149: 150: if ($token->[2]->{'condition'}) { 151: $undercond=$lpc.'.'.$token->[2]->{'condition'}; 152: } 153: 154: $hash{'goesto_'.$linkid}=$goesto; 155: $hash{'comesfrom_'.$linkid}=$comesfrom; 156: $hash{'undercond_'.$linkid}=$undercond; 157: 158: if (defined($hash{'to_'.$comesfrom})) { 159: $hash{'to_'.$comesfrom}.=','.$linkid; 160: } else { 161: $hash{'to_'.$comesfrom}=''.$linkid; 162: } 163: if (defined($hash{'from_'.$goesto})) { 164: $hash{'from_'.$goesto}.=','.$linkid; 165: } else { 166: $hash{'from_'.$goesto}=''.$linkid; 167: } 168: } 169: 170: } 171: } 172: 173: } else { 174: $errtext.='Map not loaded: The file does not exist. '; 175: } 176: } 177: 178: # --------------------------------------------------------- Simplify expression 179: 180: sub simplify { 181: my $expression=shift; 182: # (8)=8 183: $expression=~s/\((\d+)\)/$1/g; 184: # 8&8=8 185: $expression=~s/(\D)(\d+)\&\2(\D)/$1$2$3/g; 186: # 8|8=8 187: $expression=~s/(\D)(\d+)\|\2(\D)/$1$2$3/g; 188: # (5&3)&4=5&3&4 189: $expression=~s/\((\d+)((?:\&\d+)+)\)\&(\d+\D)/$1$2\&$3/g; 190: # (((5&3)|(4&6)))=((5&3)|(4&6)) 191: $expression=~ 192: s/\((\(\(\d+(?:\&\d+)*\)(?:\|\(\d+(?:\&\d+)*\))+\))\)/$1/g; 193: # ((5&3)|(4&6))|(1&2)=(5&3)|(4&6)|(1&2) 194: $expression=~ 195: s/\((\(\d+(?:\&\d+)*\))((?:\|\(\d+(?:\&\d+)*\))+)\)\|(\(\d+(?:\&\d+)*\))/\($1$2\|$3\)/g; 196: return $expression; 197: } 198: 199: # -------------------------------------------------------- Build condition hash 200: 201: sub traceroute { 202: my ($sofar,$rid,$beenhere)=@_; 203: $sofar=simplify($sofar); 204: unless ($beenhere=~/\&$rid\&/) { 205: $beenhere.=$rid.'&'; 206: if (defined($hash{'conditions_'.$rid})) { 207: $hash{'conditions_'.$rid}=simplify( 208: '('.$hash{'conditions_'.$rid}.')|('.$sofar.')'); 209: } else { 210: $hash{'conditions_'.$rid}=$sofar; 211: } 212: if (defined($hash{'is_map_'.$rid})) { 213: if (defined($hash{'map_start_'.$hash{'src_'.$rid}})) { 214: &traceroute($sofar,$hash{'map_start_'.$hash{'src_'.$rid}},'&'); 215: if (defined($hash{'map_finish_'.$hash{'src_'.$rid}})) { 216: $sofar= 217: $hash{'conditions_'.$hash{'map_finish_'.$hash{'src_'.$rid}}}; 218: } 219: } 220: } 221: if (defined($hash{'to_'.$rid})) { 222: map { 223: my $further=$sofar; 224: if ($hash{'undercond_'.$_}) { 225: if (defined($hash{'condid_'.$hash{'undercond_'.$_}})) { 226: $further=simplify('('.$further.')&('. 227: $hash{'condid_'.$hash{'undercond_'.$_}}.')'); 228: } else { 229: $errtext.='Undefined condition ID: ' 230: .$hash{'undercond_'.$_}.'. '; 231: } 232: } 233: &traceroute($further,$hash{'goesto_'.$_},$beenhere); 234: } split(/\,/,$hash{'to_'.$rid}); 235: } 236: } 237: } 238: 239: # ------------------------------------------ Cascading conditions, quick access 240: 241: sub accinit { 242: my ($uri,$short,$fn)=@_; 243: my %acchash=(); 244: my %captured=(); 245: my $condcounter=0; 246: $acchash{'acc.cond.'.$short.'.0'}=0; 247: map { 248: if ($_=~/^conditions/) { 249: my $expr=$hash{$_}; 250: map { 251: my $sub=$_; 252: my $orig=$_; 253: $sub=~/\(\((\d+\&(:?\d+\&)*)(?:\d+\&*)+\)(?:\|\(\1(?:\d+\&*)+\))+\)/; 254: my $factor=$1; 255: $sub=~s/$factor//g; 256: $sub=~s/^\(/\($factor\(/; 257: $sub.=')'; 258: $sub=simplify($sub); 259: $orig=~s/(\W)/\\$1/g; 260: $expr=~s/$orig/$sub/; 261: } ($expr=~m/(\(\(\d+(?:\&\d+)+\)(?:\|\(\d+(?:\&\d+)+\))+\))/g); 262: $hash{$_}=$expr; 263: unless (defined($captured{$expr})) { 264: $condcounter++; 265: $captured{$expr}=$condcounter; 266: $acchash{'acc.cond.'.$short.'.'.$condcounter}=$expr; 267: } 268: } 269: } keys %hash; 270: map { 271: if ($_=~/^ids/) { 272: my $resid=$hash{$_}; 273: my $uri=$hash{'src_'.$resid}; 274: my @uriparts=split(/\//,$uri); 275: my $urifile=$uriparts[$#uriparts]; 276: $#uriparts--; 277: my $uripath=join('/',@uriparts); 278: if (defined($hash{'conditions_'.$resid})) { 279: $urifile.=':'.$captured{$hash{'conditions_'.$resid}}; 280: } else { 281: $urifile.=':0'; 282: } 283: if (defined($acchash{'acc.res.'.$short.'.'.$uripath})) { 284: $acchash{'acc.res.'.$short.'.'.$uripath}.=$urifile.'&'; 285: } else { 286: $acchash{'acc.res.'.$short.'.'.$uripath}='&'.$urifile.'&'; 287: } 288: } 289: } keys %hash; 290: &Apache::lonnet::appenv(%acchash, 291: "request.course" => $short, 292: "request.course.fn" => $fn); 293: } 294: 295: # ---------------------------------------------------- Read map and all submaps 296: 297: # 298: # Call with uri of course map, short name for course, and filename for 299: # binary structure 300: # 301: 302: sub readmap { 303: my ($uri,$short,$fn)=@_; 304: @cond=('true:normal'); 305: if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_WRCREAT,0640)) { 306: %hash=(); 307: $errtext=''; 308: $pc=0; 309: loadmap($uri); 310: if (defined($hash{'map_start_'.$uri})) { 311: &traceroute('0',$hash{'map_start_'.$uri},'&'); 312: &accinit($uri,$short,$fn); 313: } 314: unless (untie(%hash)) { 315: &Apache::lonnet::logthis("<font color=blue>WARNING: ". 316: "Could not untie coursemap $fn for $uri.</font>"); 317: } 318: { 319: my $cfh; 320: if ($cfh=Apache::File->new(">$fn.state")) { 321: print $cfh join("\n",@cond); 322: } else { 323: &Apache::lonnet::logthis("<font color=blue>WARNING: ". 324: "Could not write statemap $fn for $uri.</font>"); 325: } 326: } 327: } else { 328: &Apache::lonnet::logthis("<font color=blue>WARNING: ". 329: "Could not tie coursemap $fn for $uri.</font>"); 330: } 331: return $errtext; 332: } 333: 334: 1; 335: __END__ 336: 337: 338: 339: 340: 341: 342: