Parent Directory
|
Revision Log
1. better guess for system HTML dir. 2. default perl path is now "/usr/bin/env perl". 3. a warning is given directing users with commit privs to refrain from changing the perl path.
1 #!/usr/bin/env perl 2 3 ################################################################################ 4 # WeBWorK 5 # 6 # Copyright (c) 1995-2001 WeBWorK Team, University of Rochester 7 # All rights reserved 8 # 9 # $Id$ 10 ################################################################################ 11 12 #################### initialization 13 14 require 5.000; 15 use Cwd; 16 use File::Copy; 17 18 # define built-in defaults 19 my $DEFAULT_PERL_PATH = '/usr/bin/env perl'; 20 my $DEFAULT_CGI_URL = '/cgi-bin/webwork/system/'; 21 my $DEFAULT_HTML_URL = '/webwork_system_html/'; 22 my $DEFAULT_ADMIN_GROUP = 'wwadmin'; 23 24 # define code strings 25 my $CGI_DEBUG_TAG = 'WeBWorKCGIDebugURL'; 26 my $CGI_NODEBUG_TAG = 'WeBWorKCGINoDebugURL'; 27 my $LIB_INIT_LINE_TAG = 'WeBWorKInitLine'; 28 29 # scope and undefine setup variables 30 $no_prompts = undef; 31 $system_setup_mode = undef; 32 $mainDir = undef; 33 $perlPath = undef; 34 $cgiURL = undef; 35 $htmlURL = undef; 36 $htmlDir = undef; 37 $groupName = undef; 38 $update_stuff_in_courses = undef; 39 $chgrp_files_and_dirs = undef; 40 $chmod_files_and_dirs = undef; 41 $local_preprocessor = undef; 42 $local_postprocessor = undef; 43 44 # read defaults in from defaults file 45 my $DEFAULTS_FILE; 46 if($ARGV[0] and $ARGV[0] eq '-d') { 47 if($ARGV[1]) { $DEFAULTS_FILE = $ARGV[1]; } 48 else { $DEFAULTS_FILE = ((getpwuid $<)[7]) . '/system_webwork_setup.defaults'; } 49 if(-e $DEFAULTS_FILE) { 50 print "Reading defaults file..."; 51 require $DEFAULTS_FILE; 52 print " done.\n"; 53 } 54 } 55 56 #################### text strings 57 58 my $INTRO_TEXT = q{ 59 +----------------------+ 60 | System Webwork Setup | 61 +----------------------+ 62 63 This script is used to setup the main WeBWorK system. It will create 64 initialization files, set groups and permissions for files and directories, 65 and modify files. A "demo" or "working" version of the system can be setup. 66 67 You will need the following information: 68 69 1) The location of your WeBWorK system directory. 70 Example: /usr/local/webwork/system/ 71 Example: /var/www/webwork/system/ 72 73 2) The path to perl on your system. 74 Example: /usr/bin/perl 75 Example: /usr/local/bin/perl 76 77 3) The group containing the users who have the authority to modify the 78 webwork system files. Who ever runs this script must be a member of 79 this group. (Note: This is not required for the demo mode.) 80 Example: wwadmin 81 82 4) The URL to the WeBWorK CGI scripts. 83 Example: /cgi-bin/webwork/system/ (preferred) 84 85 5) The URL to the static system_html files. 86 Example: /webwork_system_html/ 87 88 }; 89 90 my $MODE_TEXT = q{ 91 92 You can set up a "working" or a "demo" WeBWorK system. A "demo" system 93 should only be used as a sample system, never for a system that will be used 94 with actual courses with real students. The main difference between a 95 "working" version and a "demo" version is that in a "working" version you 96 will be promped to enter a group (e.g. wwadmin) where as in a "demo" 97 version, the group will be set yo your own default group (e.g. fac). Anyone 98 in the group will have permission to modify all webwork files. You can set 99 up "working" and "demo" courses under either a "working" or a "demo" system, 100 but normally you would not set up a "working" course under a "demo" system. 101 102 }; 103 104 my $MAIN_DIR_TEXT = q{ 105 106 The directory containing the WeBWorK system files (as well as this 107 script) is known as the system directory. In order to modify system 108 files, I need to know the location of the system directory for this 109 installation. 110 111 }; 112 113 my $PERL_TEXT = q{ 114 115 WeBWorK needs to know the path of your perl binary, so that this 116 information can be used in the headers of cgi scripts. Please make sure 117 that the version of perl you specify is 5.004 or later. 118 119 If you have commit access to the WeBWorK system repository, you MUST 120 leave this as "/usr/bin/env perl". 121 122 }; 123 124 my $CGI_URL_TEXT = q{ 125 126 In order for generated HTML to be able to invoke CGI scripts, WeBWorK 127 needs to know the URL which points to the main WeBWorK system cgi 128 subdirectory. If both static HTML and CGIs reside on the same host 129 (which is true in most cases), you can omit the http://hostname section 130 of the URL, but make sure the leading slash is present. 131 132 }; 133 134 my $HTML_DIR_TEXT = q{ 135 136 The directory containing the WeBWorK system HTML files is known as the system 137 HTML directory. In order to dynamically generate system-wide public resources, I 138 need to know the location of the system HTML directory for this installation. 139 140 }; 141 142 my $HTML_URL_TEXT = q{ 143 144 WeBWorK also needs to know the URL of the main HTML directory, the 145 system_html subdirectory. If both static HTML and CGIs reside on the 146 same host (which is true in most cases), you can omit the 147 http://hostname section of the URL, but make sure the leading slash is 148 present. 149 150 }; 151 152 my $GROUP_TEXT = q{ 153 154 WeBWorK needs to know what the admin group is. This group should have been 155 set up by your system administrator and must contain at least your user ID. 156 All files and directories created will have this as their group. 157 158 }; 159 160 my $COURSE_PERMS_TEXT = q{ 161 162 You have the option to set permissions for the courses directory. If this is 163 an inital setup, you should probably do so. If this is not an initial setup, 164 the courses directory is already set up, or the courses directory is shared 165 between WeBWorK installations, your probably shouldn't. 166 167 }; 168 169 my $CHGRP_TEXT = q{ 170 171 You have to option to set the group for all system files and directories. If 172 this is an initial setup, you should probably do this. If this is not an 173 initial setup, or you have customized the way system files should be 174 grouped, you probably shoudn't. 175 176 }; 177 178 my $CHMOD_TEXT = q{ 179 180 You have to option to set the permissions for all system files and 181 directories. If this is an initial setup, you should probably do this. If 182 this is not an initial setup, or you have customized the permissions for the 183 system files, you probably shoudn't. 184 185 }; 186 187 my $CONFIRM_TEXT = q{ 188 189 Now that I have the necessary information, I can begin modifying the WeBWorK 190 system files. 191 192 }; 193 194 my $DONE_TEXT = q{ 195 196 The system setup script is done. Please read the above messages 197 carefully to determine if there have been any errors. If so, correct the 198 problem (usually a permissions problem) and run this script again. 199 200 }; 201 202 203 204 205 206 ################################################################################ 207 ########## Ask some questions, perform some logic. ############################# 208 ################################################################################ 209 210 211 212 213 214 #################### introduction 215 216 my $temp; 217 218 unless($no_prompts) { 219 page($INTRO_TEXT); 220 $temp = questionChar("Do you want to continue with setup?", 'y', 'y', 'n'); 221 exit unless $temp eq 'y'; 222 } 223 print "Okay, here we go...\n"; 224 225 #################### working or demo? 226 227 unless(defined $system_setup_mode) { 228 page($MODE_TEXT); 229 $temp = questionChar("Shall we set up a working version or a demo version?", 'w', 'w', 'd'); 230 $system_setup_mode = "working" if $temp eq 'w'; 231 $system_setup_mode = "demo" if $temp eq 'd'; 232 } 233 print "System setup mode is: $system_setup_mode\n"; 234 235 #################### main directory 236 237 unless(defined $mainDir) { 238 page($MAIN_DIR_TEXT); 239 $mainDir = questionString("Where is the WeBWorK system directory?", cwd()); 240 $mainDir .= '/' unless $mainDir =~ m|/$|; # ensure trailing slash 241 } 242 print "We'll use $mainDir as WeBWorK's system directory.\n"; 243 244 #################### perl path 245 246 unless(defined $perlPath) { 247 page($PERL_TEXT); 248 $perlPath = questionString("What is the full path to PERL?", $DEFAULT_PERL_PATH); 249 } 250 print "Path to PERL binary is: $perlPath\n"; 251 252 #################### CGI URL 253 254 unless(defined $cgiURL) { 255 page($CGI_URL_TEXT); 256 while (1) { 257 $cgiURL = questionString("What is the CGI URL?", $DEFAULT_CGI_URL); 258 if( ($cgiURL =~ m|^/|) or ($cgiURL =~ m|^http://|) ) { 259 last; 260 } else { 261 $temp = questionChar("That doesn't look like a valid URL. Would you like to use it anyway?", 'n', 'y', 'n'); 262 last if $temp eq 'y'; 263 } 264 } 265 $cgiURL .= "/" unless $cgiURL =~ m"/$"; # ensure trailing slash 266 } 267 print "CGI URL is: $cgiURL\n"; 268 269 #################### system HTML directory 270 271 unless(defined $htmlDir) { 272 page($HTML_DIR_TEXT); 273 my $htmlDirGuess = ${mainDir}; 274 $htmlDirGuess =~ s|[^/]+/$|system_html/|; 275 $htmlDir = questionString("Where is the WeBWorK system HTML directory?", $htmlDirGuess); 276 $htmlDir .= '/' unless $htmlDir =~ m|/$|; # ensure trailing slash 277 } 278 print "We'll use $htmlDir as WeBWorK's system HTML directory.\n"; 279 280 #################### HTML URL 281 282 unless(defined $htmlURL) { 283 page($HTML_URL_TEXT); 284 while (1) { 285 $htmlURL = questionString("What is the HTML URL?", $DEFAULT_HTML_URL); 286 if( ($htmlURL =~ m|^/|) or ($htmlURL =~ m|^http://|) ) { 287 last; 288 } else { 289 $temp = questionChar("That doesn't look like a valid URL. Would you like to use it anyway?", 'n', 'y', 'n'); 290 last if $temp eq 'y'; 291 } 292 } 293 $htmlURL .= "/" unless $htmlURL =~ m"/$" ; 294 } 295 print "HTML URL is: $htmlURL\n"; 296 297 #################### admin group 298 299 unless(defined $groupName) { 300 my ($userName, $userGID) = (getpwuid $<)[0,3]; 301 my $userGroupName = (getgrgid $userGID)[0]; 302 303 if ($system_setup_mode eq 'demo') { 304 # in demo mode, the group is set to the user's primary group 305 $groupName = $userGroupName; 306 } else { 307 # in working mode, we get to chose 308 page($GROUP_TEXT); 309 while(1) { 310 $groupName = questionString("What is the admin group name?", $DEFAULT_ADMIN_GROUP); 311 my @group = getgrnam $groupName; 312 unless(@group) { 313 print "$groupName does not exist.\n"; 314 next; 315 } 316 my @members = split / /, $group[3]; 317 if($groupName eq $userGroupName) { 318 print "$groupName is ${userName}'s primary group. Good.\n"; 319 last; 320 } elsif(grep { $_ eq $userName } @members) { 321 print "$userName is a member of $groupName. Good.\n"; 322 last; 323 } elsif($< == 0) { # we're root! 324 print "$userName isn't a member of $groupName, but you're root, so who cares?\n"; 325 last; 326 } else { 327 print "$groupName is not a valid group. Please make sure the group exists and $userName are a member.\n"; 328 } 329 } 330 } 331 } 332 print "Admin group is: $groupName\n"; 333 334 #################### chmod courses directory 335 336 unless(defined $update_stuff_in_courses) { 337 page($COURSE_PERMS_TEXT); 338 $temp = questionChar("Do you want to set default $system_setup_mode permissions for the courses directory?", 'y', 'y', 'n'); 339 $update_stuff_in_courses = ($temp eq 'y'); 340 } 341 print "Permissions ", ($update_stuff_in_courses ? "will" : "will not"), " be set for the courses directory.\n"; 342 343 344 #################### chgrp files/directories 345 346 $system_setup_mode eq "demo" and $chgrp_files_and_dirs = 1; 347 unless(defined $chgrp_files_and_dirs) { 348 page($CHGRP_TEXT); 349 $temp = questionChar("Do you want to set the group for system files and directories?", 'y', 'y', 'n'); 350 $chgrp_files_and_dirs = ($temp eq 'y'); 351 } 352 print "Group ", ($chgrp_files_and_dirs ? "will" : "will not"), " be set for system files and directories.\n"; 353 354 #################### chmod files/directories 355 356 $system_setup_mode eq "demo" and $chmod_files_and_dirs = 1; 357 unless(defined $chmod_files_and_dirs) { 358 page($CHMOD_TEXT); 359 $temp = questionChar("Do you want to set the permissions for system files and directories?", 'y', 'y', 'n'); 360 $chmod_files_and_dirs = ($temp eq 'y'); 361 } 362 print "Permissions ", ($chmod_files_and_dirs ? "will" : "will not"), " be set for system files and directories.\n"; 363 364 #################### make sure we want to actually do this 365 366 unless($no_prompts) { 367 print $CONFIRM_TEXT; 368 $temp = questionChar("Do you want to continue with setup?", 'y', 'y', 'n'); 369 exit unless $temp eq 'y'; 370 } 371 print "\Going to make changes now...\n\n"; 372 373 374 375 376 377 ################################################################################ 378 ########## Now we start changing things... ##################################### 379 ################################################################################ 380 381 382 383 384 385 #################### run local preprocessor 386 387 if(defined $local_preprocessor) { 388 print "Executing local preprocessor...\n"; 389 &$local_preprocessor; 390 print "Done with local preprocessor.\n"; 391 } 392 393 #################### update #! and use lines 394 # uses: $mainDir, $perlPath 395 396 print "Fixing #! lines...\n"; 397 398 foreach my $dir ("${mainDir}cgi/cgi-scripts", "${mainDir}scripts", "${mainDir}courseScripts") { 399 foreach my $file (<${dir}/*.pl>) { 400 fixFile($file); 401 } 402 } 403 404 sub fixFile 405 { 406 my ($file) = @_; 407 408 # read the file 409 open FILE, $file || die "Couldn't open $file for reading."; 410 my @lines = <FILE>; 411 close FILE || die "Couldn't close $file after reading."; 412 413 # fix perl path 414 $lines[0] =~ m/^#!(.*)$/; 415 if($1 ne $perlPath) { 416 $lines[0] =~ s/^#!.*$/#!$perlPath/; 417 open FILE, ">$file" || die "Couldn't open $file for writing."; 418 print FILE @lines; 419 close FILE || die "Couldn't close $file for writing."; 420 } 421 } 422 423 print "done fixing #! and \"use\" lines.\n\n"; 424 425 #################### write webworkConfig.pm file 426 # uses: $mainDir, $cgiURL, $htmlDir, $htmlURL 427 428 print "Writing lib/webworkConfig.pm file...\n"; 429 open CONFIG_FILE, ">${mainDir}lib/webworkConfig.pm"; 430 print CONFIG_FILE<<END_OF_CONFIG_FILE; 431 package Global; 432 433 ################################################################################ 434 # WeBWorK 435 # 436 # Copyright (c) 1995-2001 WeBWorK Team, University of Rochester 437 # All rights reserved 438 ################################################################################ 439 440 # \$cgiDebugMode, if enabled, will call the debug wrapper scripts instead of the 441 # cgi scripts themselves, allowing for header output, etc. In addition to 442 # setting \$cgiDebugMode =1, you will also need to enable debugging in the 443 # wrapper scripts that you wish to debug, by setting \$debug = 1. Wrapper 444 # scripts are found in the directory referred to by \$cgiWebworkURL, which is 445 # usually webwork/system/cgi. 446 \$cgiDebugMode = 0; 447 448 \$mainDirectory = "$mainDir"; 449 \$htmlWebworkDir = "$htmlDir"; 450 \$htmlWebworkURL = "$htmlURL"; 451 \$cgiWebworkURL = "$cgiURL"; 452 \$cgiWebworkURL .= "cgi-scripts/" unless \$cgiDebugMode; 453 454 1; 455 END_OF_CONFIG_FILE 456 close CONFIG_FILE; 457 print "Done writing lib/webworkConfig.pm file.\n\n"; 458 459 #################### write webworkInit.pm files 460 # uses: $mainDir 461 462 print "Writing webworkInit.pm files...\n"; 463 foreach my $dir ('cgi/', 'cgi/cgi-scripts/', 'scripts/') { 464 open INIT_FILE, ">$mainDir${dir}webworkInit.pm"; 465 print INIT_FILE<<END_OF_INIT_FILE; 466 ################################################################################ 467 # WeBWorK 468 # 469 # Copyright (c) 1995-2001 WeBWorK Team, University of Rochester 470 # All rights reserved 471 ################################################################################ 472 473 use lib '${mainDir}lib/'; 474 use lib '${mainDir}courseScripts/'; 475 476 1; 477 END_OF_INIT_FILE 478 close INIT_FILE; 479 } 480 print "Done writing webworkInit.pm files.\n\n"; 481 482 #################### chgrp system stuff 483 # uses: $chgrp_files_and_dirs, $groupName 484 485 if($chgrp_files_and_dirs) { 486 print "Setting group on system files and directories...\n"; 487 system "chgrp -R $groupName $mainDir"; 488 system "chgrp -R $groupName $mainDir/../system_html"; 489 system "chgrp -R $groupName $mainDir/../pg"; 490 print "Done setting group.\n\n"; 491 } 492 493 #################### chmod system stuff 494 # uses: $chmod_files_and_dirs 495 496 if($chmod_files_and_dirs) { 497 print "Setting permissions on system files and directories for $system_setup_mode mode...\n"; 498 if ($system_setup_mode eq "demo") { 499 # get some general permissions for files and directories 500 system "find $mainDir $mainDir/../system_html -type d -print | xargs chmod 0755"; 501 system "find $mainDir $mainDir/../system_html -type f -print | xargs chmod 0644"; 502 system "find $mainDir $mainDir/../pg -type d -print | xargs chmod 0755"; 503 system "find $mainDir $mainDir/../pg -type f -print | xargs chmod 0644"; 504 # add executable privs to scripts 505 system "find ${mainDir}cgi ${mainDir}scripts -type f -print | xargs chmod 0755"; 506 } else { 507 # get some general permissions for files and directories 508 system "find $mainDir $mainDir/../system_html -type d -print | xargs chmod 0775"; 509 system "find $mainDir $mainDir/../system_html -type f -print | xargs chmod 0664"; 510 system "find $mainDir $mainDir/../pg -type d -print | xargs chmod 0775"; 511 system "find $mainDir $mainDir/../pg -type f -print | xargs chmod 0664"; 512 # add executable privs to scripts 513 system "find ${mainDir}cgi ${mainDir}scripts -type f -print | xargs chmod 0775"; 514 } 515 # make the log files group writable 516 system "find $mainDir/logs -type f -print | xargs chmod 0664"; 517 # make the error_log file world writable 518 system "find $mainDir/logs/error_log -print | xargs chmod 0666"; 519 520 print "done setting permissions.\n\n"; 521 } 522 523 #################### update couses stuff 524 # uses: $update_stuff_in_courses 525 526 if($update_stuff_in_courses) { 527 print "Setting permissions for ../courses directory...\n"; 528 if ($system_setup_mode eq "demo") { 529 chmod(0755, "$mainDir/../courses") or warn "Warning: I can't set permissions for ../courses directory. It's possible that the directory doesn't exist or you don't have permission to change it.\n"; 530 } else { 531 chmod(0775, "$mainDir/../courses") or warn "Warning: I can't set permissions for ../courses directory. It's possible that the directory doesn't exist or you don't have permission to change it.\n"; 532 } 533 print "done permissions.\n\n"; 534 } 535 536 #################### run local postprocessor 537 538 if(defined $local_postprocessor) { 539 print "Executing local postprocessor...\n"; 540 &$local_postprocessor; 541 print "Done with local postprocessor.\n"; 542 } 543 544 #################### finish up 545 546 page($DONE_TEXT); 547 548 ################################################################################ 549 550 sub page 551 { 552 my @string_lines = split /^/, shift; #/ 553 # not really optimal, but we're going to assume a constant screen height. 554 my $SCREEN_HEIGHT = 20; 555 while(@string_lines) { 556 print join "", @string_lines[0..($SCREEN_HEIGHT>scalar @string_lines ? (scalar @string_lines)-1 : $SCREEN_HEIGHT-1)]; 557 if(scalar @string_lines >= $SCREEN_HEIGHT) { 558 print "\n[Press ENTER to continues...]"; 559 <STDIN>; 560 print "\n"; 561 } 562 @string_lines = @string_lines[$SCREEN_HEIGHT..$#string_lines]; 563 } 564 } 565 566 sub questionChar 567 { 568 my ($question, $default, @valid) = @_; 569 my $answer; 570 do { 571 print $question, " "; 572 foreach (@valid) { 573 $_ eq $default and print "["; 574 print $_; 575 $_ eq $default and print "]"; 576 } 577 print " "; 578 $answer = <STDIN>; 579 $answer =~ s/^\s*//; 580 $answer = substr $answer, 0, 1; 581 $answer = lc $answer; 582 $answer or $answer = $default; 583 } while (not grep(/$answer/, @valid)); 584 return $answer; 585 } 586 587 sub questionString 588 { 589 my ($question, $default, $emptyOK) = @_; 590 my $answer; 591 print $question, " [", $default, "] "; 592 $answer = <STDIN>; 593 chomp $answer; 594 $answer =~ s/^\s*//; 595 $answer or $answer = $default; 596 return $answer; 597 } 598 599 __END__ 600 601 =head1 NAME 602 603 system_webwork_setup.pl - set up the WeBWorK system 604 605 =head1 SYNOPSIS 606 607 system_webwork_setup.pl [B<-d> [defaults-file]] 608 609 =head1 DESCRIPTION 610 611 B<system_webwork_setup.pl> gathers the information necessary for configuration of the WeBWorK system. It then edits several WeBWorK system files, and creates F<webworkInit.pm> modules and the F<webworkConfig.pm> module based on the information gathered. It can optionally read defaults from a file specified on the command line or from the file F<$HOME/system_webwork_setup.defaults>. 612 613 =head1 OPTIONS 614 615 =over 4 616 617 =item B<-d> 618 619 enables defaults-file processing. If no defaults-file is specified, the file F<$HOME/system_webwork_setup.defaults> will be used. 620 621 =head1 DEFAULTS 622 623 The F<system_webwork_setup.defaults> file is intended to be used in a situation where B<system_webwork_setup.pl> must be executed frequently, such as in the case of use with CVS, in which the it must be executed after a checkout and some updates. The defaults file is a perl script that will be require'd by B<system_webwork_setup.pl>. It can set any of the following variables in the usual way: 624 625 =over 4 626 627 =item $no_prompts 628 629 Refrain from prompting at the beginning of the script and before making changes. Also supresses the introductory text. 630 631 =item $system_setup_mode 632 633 Can be set to "working" or "demo". This affects how system file permissions and group ownership are set. In "working" mode, system files are group owned by a webwork admin group (see I<$groupName>) and group writeable while in "demo" mode files are group owned by the current user's default group and are not group writeable. 634 635 =item $mainDir 636 637 Specify WeBWorK's main directory, which should contain the directories cgi/ scripts/ courseScripts/ and lib/. 638 639 =item $perlPath 640 641 Specify the path to the perl interpreter which should be used. This is used to set the shebang line in cgi-scripts and scripts. 642 643 =item $cgiURL 644 645 Specify the externally visible URL to the CGI directory (typically cgi/cgi-scripts/). This will be used when scripts call other scripts. 646 647 =item $htmlURL 648 649 Specify the externally visible URL to the HTML directory (typically system_html/). This will be used when scripts refer to static graphics and text. 650 651 =item $groupName 652 653 When in "working" mode, I<$groupName> is the name of the WeBWorK admin group, members of which should have write access to the system files. (The web server should not be in this group!) 654 655 =item $update_stuff_in_courses 656 657 If true, B<system_webwork_setup.pl> will set permissions in the courses directory and prepare the B<course_webwork_setup.pl> script for execution. 658 659 =item $chgrp_files_and_dirs, $chmod_files_and_dirs 660 661 If true, the group and/or permissions on system files will be set according to I<$system_setup_mode>. 662 663 =item $local_preprocessor, $local_postprocessor 664 665 If set, these variables will be called as subroutine references. I<$local_preprocessor> is called before any changes take place, while I<$local_postprocessor> is called after all changes have taken place. 666 667 =back 668 669 =head1 FILES 670 671 $HOME/system_webwork_setup.defaults 672 673 =head1 AUTHOR 674 675 Samuel Hathaway <sh002i@math.rochester.edu>
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |