#!/usr/bin/perl -w
#
# TWiki Enterprise Collaboration Platform, http://TWiki.org/
#
# Copyright (C) 2000-2006 TWiki Contributors.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. For
# more details read LICENSE in the root of this distribution.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# As per the GPL, removal of this notice is prohibited.
#
# Configuration script for TWiki. Once you have a basic webserver
# configuration that lets you access this script, the rest of the
# configuration process is done from here. This script replaces
# the old "testenv" script.
#
# The script works by accepting values into a CGI form, and then
# submitting those values back to itself with a parameter (update)
# set to 1. This causes it to write config changes to LocalSite.cfg.
# Note that changes are only written if there is a real change in the
# value.
#
# The values available to configuration are determined by parsing
# TWiki.cfg. Special full-line comments guide the parse:
# Any comment of the form
#---+ Some text
# is taken as a foldable block, and following comments are dragged in too.
# ---++ is H3, ---+++ is H4 etc
# Comments of the form
# **TYPE opts**
# where TYPE is one of URL, PATH, URLPATH, BOOLEAN, STRING, REGEX, SELECT
# are used to indicate that a following cfg var is configurable through
# the interface. All intermediate comments are taken as documentation for
# the value.
#
package TWiki;

# BASIC checks. Without these, nothing works.

use strict;

$SIG{__DIE__} = sub { Carp::confess( $_[0] || '' ) };
$SIG{'__WARN__'} = sub { die @_ };

use vars qw( %cfg
             $perlver
             $perlvernum
             $perlverRequired
             $perlverRequiredString
             $perlverRecommended
             $perlVerPreferred
             $ActivePerlRecommendedBuild
             $GUESSED
             $cgiModVerRecommended
             $modPerlVersionRecommended
             $rcsverRequired
           );

# Constants
$perlvernum = $];
$perlverRequired = 5.00503;        # Oldest supported version of Perl
$perlverRequiredString = '5.005_03';
$perlverRecommended = '5.6.1';
$perlVerPreferred = 5.006;    # 5.6 or higher has [:lower:] etc
$ActivePerlRecommendedBuild = 631;    # Fixes PERL5SHELL bugs
$GUESSED = <<'HERE';
I guessed this setting. You are advised to confirm this setting (and any other guessed settings) and hit 'Next' to save before changing any other settings.
HERE

# CGI.pm version, on some platforms - actually need CGI 2.93 for mod_perl
# 2.0 and CGI 2.90 for Cygwin Perl 5.8.0.  See 
# http://perl.apache.org/products/apache-modules.html#Porting_CPAN_modules_to_mod_perl_2_0_Status
$cgiModVerRecommended = '2.93';

# Recommended mod_perl version if using mod_perl 2.0
# (see Support.RegistryCookerBadFileDescriptor)
$modPerlVersionRecommended = '1.99_12';

$rcsverRequired = 5.7;

# constants used in TWiki.cfg
use vars qw($TRUE $FALSE );
use vars qw( $basicMods $requiredMods $requiredModsNonUnix $optionalMods
             $I18Mods $I18Mods_perl56 $I18Mods_perl58 );

BEGIN {
    $TRUE = 1;
    $FALSE = 0;
    # Set default current working directory
    if( $ENV{SCRIPT_FILENAME} && $ENV{SCRIPT_FILENAME} =~ /^(.+)\/[^\/]+$/ ) {
        chdir $1;
    }
    # Get Perl version
    if (defined $^V) {
        $perlver = $^V;             # New in Perl 5.6.1, one byte per part
        $perlver = ord(substr($perlver,0)) . "." . ord(substr($perlver,1))
          . "." . ord(substr($perlver,2));
    } else {
        $perlver = $perlvernum
    }

    # Required for configure to work
    $basicMods =
      {
          'CGI'             => "basic TWiki",
          'CGI::Carp'       => "basic TWiki",
          'Error'           => 'basic TWiki',
      };
    $requiredMods =
      {
          'File::Copy'      => 'basic TWiki',
          'File::Spec'      => 'basic TWiki',
          'FileHandle'      => 'basic TWiki',
          'Algorithm::Diff' => 'basic TWiki',
      };

    # Required on non-Unix platforms (mainly Windows)
    $requiredModsNonUnix =
      {
          'MIME::Base64' => "SHA1 password encoding",
          'Net::SMTP'    => "registration emails and mailnotify",
      };
    # Optional modules on all platforms
    $optionalMods =
      {
          'Digest::SHA1'     => "SHA1 password encoding",
          'MIME::Base64'     => "HTTP Authentication to proxies, and SHA1 password encoding",
          'POSIX'            => "I18N (core module) and Security",
          'Digest::MD5'      => "MD5 encoded passwords",
          'Text::Diff'       => 'UpgradeTWiki',
          'CGI::Cookie'      => "sessions",
          'CGI::Session'     => "sessions",
      };

    $I18Mods =
    {
        'Locale::Maketext::Lexicon' => "I18N translations",
    };

    $I18Mods_perl56 =
      {
          'Unicode::String'  => 'I18N conversions',
          'Unicode::MapUTF8' => "I18N conversions",
          'Unicode::Map'     => "I18N conversions",
          'Unicode::Map8'    => "I18N conversions",
          'Jcode'            => "I18N conversions",
      };

    $I18Mods_perl58 =
      {
          'Encode'           => "I18N conversions (core module in Perl 5.8)",
      };
};

########################################################################
##################### GLOBAL VARIABLES #################################
########################################################################

use CGI qw( :any );

use vars qw( $cygwinRcsVerNum $perltype $query $action );

$query = new CGI;
$action = $query->param('action') || '';

if( $action eq 'image' ) {
    _serveImage( $query->param('type'), $query->param('image' ));
    exit 0;
}

use vars qw( $errors $toterrors $warnings $totwarnings $url $nextid );

$errors = 0; # reset for each block
$toterrors = 0;
$warnings = 0; # reset for each block
$totwarnings = 0;
$url = $query->url();
$nextid = 0;

########################################################################
########################## FORMATTING ##################################
########################################################################

# a note
sub NOTE {
    return CGI::p({class=>"info"}, join("\n",@_));
}

# a warning
sub WARN {
    $warnings++;
    $totwarnings++;
    return CGI::div(CGI::span({class=>'warn'}, CGI::strong('Warning: ').join("\n",@_)));
}

# an error
sub ERROR {
    $errors++;
    $toterrors++;
    return CGI::div(CGI::span({class=>'error'}, CGI::strong('Error: ').join("\n",@_)));
}

# Generate a foldable block (twisty). This is a DIV with a table in it
# that contains the settings and doc rows.
sub _foldableBlock {
    my( $head, $attr, $body ) = @_;
    my $headText = $head . CGI::span({ class => 'blockLinkAttribute' }, $attr);
    $body = CGI::start_table({width => '100%', -border => 0, -cellspacing => 0, -cellpadding => 0}).$body.CGI::end_table();
    my $mess = '';
    my $errorsMess = ($errors > 1) ? ' errors' : ' error';
    my $warningsMess = ($warnings > 1) ? ' warnings' : ' warning';
    $mess .= CGI::span({class=>'error'}, $errors . $errorsMess) if $errors;
    if ($errors && $warnings) {
        $mess .= '&nbsp;';
    }
    $mess .= CGI::span({class=>'warn'}, $warnings . $warningsMess) if $warnings;
    $errors = $warnings = 0;

    my $anchor = _makeAnchor( $head );
    my $id = $anchor;
    my $blockId = $id;
    my $linkId = 'blockLink'.$id;
    my $linkAnchor = $anchor.'link';
    return CGI::a({ name => $linkAnchor }).
           CGI::a( {id => $linkId,
                    class => 'blockLink blockLinkOff',
                    href => '#'.$linkAnchor,
                    rel => 'nofollow',
                    onclick => 'foldBlock(\'' . $id . '\'); return false;'}, $headText.$mess).
           CGI::div( { id => $blockId,
                       class=> 'foldableBlock foldableBlockClosed' }, $body ).
                       "\n";
}

# Generate an ordinary inline headedblock
sub _ordinaryBlock {
    my( $depth, $head, $attr, $body ) = @_;
    $head .= CGI::span({ class => 'blockLinkAttribute' }, $attr) if $attr;
    if( $depth == 2 ) { $head = CGI::h2( $head ); }
    elsif( $depth == 3 ) { $head = CGI::h3( $head ); }
    elsif( $depth == 4 ) { $head = CGI::h4( $head ); }
    elsif( $depth == 5 ) { $head = CGI::h5( $head ); }
    elsif( $depth == 6 ) { $head = CGI::h6( $head ); }
    else { $head = CGI::h6( $head ); }
    return CGI::Tr(CGI::td( { colspan => 2 } , $head)).
        $body;
}

# Generate a sub-heading table row
sub _subHead {
    my $text = shift;
    return CGI::Tr(CGI::Td({class=>'subHead', colspan=>2}, $text)).
      "\n";
}

# Generate a variable - prompt row
sub _setting {
    my $key = shift;
    return CGI::Tr(CGI::td({class=>'firstCol'}, $key).
                   CGI::td({class=>'secondCol'}, join(' ', @_)));
}

# generate a documentation table row
sub _docBlock {
    my $desc = shift || '';
    my $hidden = shift;
    if (length($desc) == 0 || $desc =~ /\A\s\Z/) { 
        return '';
    }
    if ($hidden) {
        return CGI::Tr( {class => 'hiddenRow' }, CGI::td( { colspan => 2, class=>'docdata info' }, $desc )).
      "\n";
    }
    return CGI::Tr( CGI::td( { colspan => 2, class=>'docdata info' }, $desc )).
      "\n";
}

# encode a string to make an HTML anchor
sub _makeAnchor {
    my $str = shift;

    $str =~ s/\s(\w)/uc($1)/ge;
    $str =~ s/\W//g;
    return $str;
}

########################################################################
################### CHECKING SUPPORT ###################################
########################################################################

# Since Windows (without Cygwin) makes it hard to capture stderr
# ('2>&1' works only on Win2000 or higher), and Windows will usually have
# GNU tools in any case (installed for TWiki since there's no built-in
# diff, grep, patch, etc), we only check for these tools on Unix/Linux
# and Cygwin.
sub _checkGnuProgram {
    my $prog = shift;
    my $n = '';

    if( $TWiki::cfg{OS} eq 'UNIX' ||
          $TWiki::cfg{OS} eq 'WINDOWS' && $perltype eq 'Cygwin' ) {
        $prog =~ s/^\s*(\S+)\s.*$/$1/;
        $prog =~ /^(.*)$/;
        $prog = $1;
        # check for taintedness
        die "$prog is tainted" unless eval { $n = $prog, kill 0; 1 };
        my $diffOut = ( `$prog --version 2>&1` || "");
        my $notFound = ( $? == -1 );
        if( $notFound ) {
            $n = WARN("'$prog' program was not found on the",
                      "current PATH.");
        } elsif ( $diffOut !~ /\bGNU\b/ ) {
            # Program found on path, complain if no GNU in version output
            $n = WARN("'$prog' program was found on the PATH",
                      "but is not GNU $prog - this may cause",
                      "problems. $diffOut");
        } else {
            $diffOut =~ /(\d+(\.\d+)+)/;
            $n = "($prog is version $1).";
        }
    }

    return $n;
}

sub _checkRCSProgram {
    my $key = shift;

    return 'Not used in this configuration.'
      unless $TWiki::cfg{StoreImpl} eq 'RcsWrap';
    my $mess = '';
    my $err = '';
    my $prog = $TWiki::cfg{RCS}{$key} || '';
    $prog =~ s/^\s*(\S+)\s.*$/$1/;
    $prog =~ /^(.*)$/; $prog = $1;
    if( !$prog ) {
        $err .= $key.' is not set';
    } else {
        my $version = `$prog -V` || '';
        if( $@ ) {
            $err .= ERROR($prog.' returned an error: '.$@ );
        } elsif ( $version ne '' ) {
            $version =~ /(\d+(\.\d+)+)/;
            $version = $1;
            $mess .= " ($prog is version $version)";
        } else {
            $err .= ERROR($prog.' did not return a version number (or might not exist..)');
        }
        if( defined( $cygwinRcsVerNum )) {
            $mess .= " (Cygwin package <tt>rcs-$cygwinRcsVerNum</tt>)";
        }
        if( $version && $version < $rcsverRequired ) {
            # RCS too old
            $err .= $prog.' is too old, upgrade to version '.
              $rcsverRequired.' or higher.';
        }
    }
    if( $err ) {
        $mess .= ERROR( $err .<<HERE
TWiki will probably not work with this RCS setup. Either correct the setup, or
switch to RcsLite. To enable RCSLite you need to change the setting of
{StoreImpl} to 'RcsLite'.
HERE
                       );
    }
    return $mess;
}

sub _checkBinDir {
    my $dir = $ENV{SCRIPT_FILENAME} || '.';
    $dir =~ s(/+configure[^/]*$)();
    my $ext = $TWiki::cfg{ScriptSuffix} || '';
    my $errs = '';
    opendir(D, $dir) or return ERROR("Cannot open $dir for read - check it exists, and that permissions are correct");
    foreach my $script (grep { -f "$dir/$_" && /^\w+(\.\w+)?$/ } readdir D) {
        next if( $ext && $script !~ /\.$ext$/ );
        if( $TWiki::cfg{OS} !~ /^Windows$/i && !-x "$dir/$script" ) {
            $errs .= WARN($script . ' might not be an executable script - please check it (and its permissions) manually');
        }
    }
    closedir(D);
    return $dir.CGI::br().$errs;
}

sub _checkCanCreateFile {
    my $name = shift;
    if (-e $name) {
        # if the file exists just check perms and return
        return _checkTreePerms($name,'rw');
    }
    my $txt1 = "test 1 2 3";
    unlink $name if( -e $name );
    open( FILE, ">$name" ) ||
      return 'Could not create test file '. $name;
    print FILE $txt1;
    close( FILE);
    open( IN_FILE, "<$name" ) ||
      return 'Could not read test file '. $name;
    my $txt2 = <IN_FILE>;
    close( IN_FILE );
    unlink $name if( -e $name );
    unless ( $txt2 eq $txt1 ) {
        return 'Could not write and then read '.$name;
    }
    return '';
}

sub _checkTreePerms {
    my( $path, $perms, $filter ) = @_;

    return '' if( defined($filter) && $path !~ $filter && !-d $path);

    #lets ignore Subversion directories
    return '' if( $path !~ /_svn/ );
    return '' if( $path !~ /.svn/ );

    my $errs = '';

    return $path. ' cannot be found'.CGI::br() unless( -e $path );

    if( $perms =~ /r/ && !-r $path) {
        $errs .= ' readable';
    }

    if( $perms =~ /w/ && !-d $path && !-w $path) {
        $errs .= ' writable';
    }

    if( $perms =~ /x/ && !-x $path) {
        $errs .= ' executable';
    }

    return $path.' is not '.$errs.CGI::br() if $errs;

    return '' unless -d $path;

    opendir(D, $path) ||
      return 'Directory '.$path.' is not readable.'.CGI::br();

    foreach my $e ( grep { !/^\./ } readdir( D )) {
        my $p = $path.'/'.$e;
        $errs .= _checkTreePerms( $p, $perms, $filter );
    }
    closedir(D);
    return $errs;
}

sub _findFileOnPath {
    my $file = shift;
    $file =~ s(::)(/)g;

    foreach my $dir ( @INC ) {
        if ( -e "$dir/$file" ) {
            return "$dir/$file";
        }
    }
    return undef;
}

# Try and locate a required directory
sub _findMajorDir {
    my( $cfg, $dir ) = @_;
    return '' if( $TWiki::cfg{$cfg} && $TWiki::cfg{$cfg} ne 'NOT SET');
    my $guess = $ENV{SCRIPT_FILENAME};
    unless( $guess ) {
        return WARN("This web server does not set SCRIPT_FILENAME so I can't guess a value for this");
    }
    $guess =~ s(bin/*configure$)();
    $guess .= $dir;
    $TWiki::cfg{$cfg} = $guess;
    return WARN($GUESSED);
}

sub _warnAboutWindowsBackSlashes {
   my ( $path ) = @_;
   if ( $path =~ /\\/ ) {
      return WARN('You should use c:/path style slashes, not c:\path in "'.$path.'"');
   }
}

########################################################################
##################### PROMPT GENERATORS ################################
########################################################################

# generate an input field for string types
sub _PROMPT_FOR_STRING {
    my( $id, $opts, $value, $keys ) = @_;
    my $size = 60;
    if( $opts =~ /\s(\d+)\s/ ) {
        $size = $1;
    }
    # support upgrade from old configuration, where LowerNational and UpperNational
    # were stored as REGEX'es (now they are STRING's):
    if ( $id eq "LowerNational" || $id eq "UpperNational" ) { 
        if ($value =~ /^\(\?-xism:(.*)\)$/) {
            $value = $1;
        }
    }

    return CGI::textfield( -name => $id, -size=>$size, -default=>$value );
}

# generate an input field for URL types
# This has its own type in case someone wants to add javascript validation
sub _PROMPT_FOR_URL {
    my( $id, $opts, $value, $keys ) = @_;
    return CGI::textfield( -name => $id, -size=>60, -default=>$value );
}

# generate an input field for URLPATH types
# This has its own type in case someone wants to add javascript validation
sub _PROMPT_FOR_URLPATH {
    my( $id, $opts, $value, $keys ) = @_;
    return CGI::textfield( -name => $id, -size=>60, -default=>$value );
}

# generate an input field for PATH types
# This has its own type in case someone wants to add javascript validation
sub _PROMPT_FOR_PATH {
    my( $id, $opts, $value, $keys ) = @_;
    return CGI::textfield( -name => $id, -size=>60, -default=>$value );
}

# generate an input field for BOOLEAN types
sub _PROMPT_FOR_BOOLEAN {
    my( $id, $opts, $value, $keys ) = @_;
    return CGI::checkbox( -name => $id, -checked => ( $value ? 1 : 0),
                          -value => 1, -label => '' );
}

# generate an input field for REGEX types
# This has its own type in case someone wants to add javascript validation
sub _PROMPT_FOR_REGEX {
    my( $id, $opts, $value, $keys ) = @_;
    return CGI::textfield( -name => $id, -size=>60, -default=>$value );
}

# generate an input field for COMMAND types
# This has its own type in case someone wants to add javascript validation
sub _PROMPT_FOR_COMMAND {
    my( $id, $opts, $value, $keys ) = @_;
    return CGI::textfield( -name => $id, -size=>60, -default=>$value );
}

# generate an input field for NUMBER types
# This has its own type in case someone wants to add javascript validation
sub _PROMPT_FOR_NUMBER {
    my( $id, $opts, $value, $keys ) = @_;
    return CGI::textfield( -name => $id, -size=>20, -default=>$value );
}

# generate an input field for OCTAL number types (protections)
sub _PROMPT_FOR_OCTAL {
    my( $id, $opts, $value, $keys ) = @_;
    return CGI::textfield( -name => $id, -size=>20,
                           -default=>sprintf('0%o',$value) );
}

# generate an input field for SELECT types
sub _PROMPT_FOR_SELECT {
    my( $id, $opts, $value, $keys ) = @_;
    $opts =~ s/^\s+//;
    $opts =~ s/\s.*$//;
    my $sopts = '';
    if ( defined($value) ) {
    	$sopts .= '<option selected="selected">'.$value.'</option>';
    }
    foreach my $opt (split( /\s*,\s*/, $opts)) {
        if( $opt ne $value ) {
            $sopts .= '<option>'.$opt.'</option>';
        }
    }
    return CGI::Select({ name => $id, size=>1 }, $sopts);
}

########################################################################
###################### VARIABLE CHECKERS ###############################
########################################################################

sub _CHECKVAR_DefaultUrlHost {
    my $keys = shift;

    if( $TWiki::cfg{DefaultUrlHost} &&
       $TWiki::cfg{DefaultUrlHost} ne 'NOT SET' ) {
        my $host = $ENV{HTTP_HOST};
        if( $host && $TWiki::cfg{DefaultUrlHost} !~ /$host/ ) {
            return WARN('Current setting does not match HTTP_HOST ',
                        $ENV{HTTP_HOST});
        }
    } else {
        my $protocol = $url || 'http://'.$ENV{HTTP_HOST};
        $protocol =~ s(^(.*?://.*?)/.*$)($1);
        $TWiki::cfg{DefaultUrlHost} = $protocol;
        return ERROR($GUESSED);
    }
    return '';
}

sub _CHECKVAR_ScriptUrlPath {
    # Check Script URL Path against REQUEST_URI
    my $n;
    my $val = $TWiki::cfg{ScriptUrlPath};
    my $guess = $ENV{REQUEST_URI} || $ENV{SCRIPT_NAME} || '';
    $guess =~ s(/+configure\b.*$)();

    if( $val && $val ne 'NOT SET' ) {
        unless( $guess ) {
            return WARN(<<HERE
This web server does not set REQUEST_URI or SCRIPT_NAME
so it isn't possible to check the correctness of this setting.
HERE
                       );
        };
        if ( $guess !~ /^$val/ ) {
            return WARN('I expected this to look like "'.$guess.'"');
        }
    } else {
        unless( $guess ) {
            return WARN(<<HERE
This web server does not set REQUEST_URI or SCRIPT_NAME
so it isn't possible to guess this setting.
HERE
                       );
        };
        $TWiki::cfg{ScriptUrlPath} = $guess;
        return ERROR($GUESSED);
    }
    return '';
}

sub _CHECKVAR_DispScriptUrlPath {
    # Check Script URL Path against REQUEST_URI
    my $n;
    my $val = $TWiki::cfg{DispScriptUrlPath};
    my $guess = $ENV{REQUEST_URI} || $ENV{SCRIPT_NAME} || '';
    $guess =~ s(/+configure[^/]*$)();

    if( !defined($val) || $val eq 'NOT SET' ) {
        $TWiki::cfg{DispScriptUrlPath} = $TWiki::cfg{ScriptUrlPath};
        return WARN($GUESSED);
    }
    return '';
}

sub _CHECKVAR_PubUrlPath {
    unless( $TWiki::cfg{PubUrlPath} && $TWiki::cfg{PubUrlPath} ne 'NOT SET') {
        my $guess = $TWiki::cfg{ScriptUrlPath};
        $guess =~ s/bin$/pub/;
        $TWiki::cfg{PubUrlPath} = $guess;
        return WARN($GUESSED);
    }
    return 'This is not set correctly if the link below is broken:'.CGI::br().
      '<a rel="nofollow" href="'.$TWiki::cfg{PubUrlPath}.'">Go to &quot;pub&quot; directory</a>';
}

sub _CHECKVAR_PubDir {
    my $e = _findMajorDir('PubDir', 'pub');
    $e .= _warnAboutWindowsBackSlashes($TWiki::cfg{PubDir});
    my $e2 = _checkTreePerms( $TWiki::cfg{PubDir}, 'rw' );
    $e .= WARN($e2) if $e2;
    return $e;
}

sub _CHECKVAR_TemplateDir {
    my $e = _findMajorDir('TemplateDir', 'templates');
    $e .= _warnAboutWindowsBackSlashes($TWiki::cfg{TemplateDir});
    my $e2 = _checkTreePerms( $TWiki::cfg{TemplateDir}, 'r' );
    $e .= ERROR($e2) if $e2;
    return $e;
}

sub _CHECKVAR_DataDir {
    my $e = _findMajorDir('DataDir', 'data');
    my $e2 = _checkTreePerms( $TWiki::cfg{DataDir}, "r" );
    $e .= _warnAboutWindowsBackSlashes($TWiki::cfg{DataDir});
    $e2 = _checkTreePerms( $TWiki::cfg{DataDir}, "w", qr/\.txt$/ )
      unless $e2;
    $e .= WARN($e2) if $e2;
    return $e;
}

sub _CHECKVAR_LocalesDir {
    my $e = _findMajorDir('LocalesDir', 'locale');
    my $e2 = _checkTreePerms( $TWiki::cfg{LocalesDir}, "r" );
    $e .= _warnAboutWindowsBackSlashes($TWiki::cfg{LocalesDir});
    $e .= ERROR($e2) if $e2;
    return $e;
}

sub _CHECKVAR_MailProgram {
    eval "use Net::SMTP";
    my $n;
    if ($@) {
        $n = "Net::SMTP is <b>not</b> installed in this environment. ";
        my $val = $TWiki::cfg{MailProgram} || '';
        $val =~ s/\s.*$//g;
        if( ! ( -e $val ) ) {
            return WARN("<tt>$val</tt> was not found. Check the path.");
        }
    } else {
        $n = 'Net::SMTP is installed in this environment, so this setting will <b>not</b> be used.';
    }
    return $n;
}

sub _CHECKVAR_LogFileName {
    my $logFile = $TWiki::cfg{LogFileName} || "";
    $logFile =~ s/%DATE%/DATE/;
    my $e = _checkCanCreateFile( $logFile );
    $e = ERROR($e) if $e;
    return $e;
}

sub _CHECKVAR_ConfigurationLogName {
    my $logFile = $TWiki::cfg{ConfigurationLogName} || "";
    $logFile =~ s/%DATE%/DATE/;
    my $e = _checkCanCreateFile( $logFile );
    $e = ERROR($e) if $e;
    return $e;
}

sub _CHECKVAR_WarningFileName {
    my $logFile = $TWiki::cfg{WarningFileName} || "";
    $logFile =~ s/%DATE%/DATE/;
    my $e = _checkCanCreateFile( $logFile );
    $e = ERROR($e) if $e;
    return $e;
}

sub _CHECKVAR_DebugFileName {
    my $logFile = $TWiki::cfg{DebugFileName} || "";
    $logFile =~ s/%DATE%/DATE/;
    my $e = _checkCanCreateFile( $logFile );
    $e = ERROR($e) if $e;
    return $e;
}

sub _CHECKVAR_MimeTypesFileName {
    my $e = _checkTreePerms($TWiki::cfg{MimeTypesFileName}, 'r');
    $e = ERROR($e) if $e;
    return $e;
}

sub _CHECKVAR_Htpasswd_FileName {
    my $e = _checkTreePerms($TWiki::cfg{Htpasswd}{FileName}, 'r');
    $e = ERROR($e) if $e;
    return $e;
}

sub _CHECKVAR_RegistrationApprovals {
    my $file = $TWiki::cfg{RegistrationApprovals};
    my $e = _checkTreePerms( $file, 'rw' );
    $e = WARN($e) if $e;
    return $e;
}

sub _CHECKVAR_UseLocale {
    my $on = $TWiki::cfg{UseLocale};

    my $n = '';
    if( $TWiki::cfg{OS} eq 'WINDOWS' ) {
        # Warn re known broken locale setup
        $n .= WARN(<<HERE
Using Perl on Windows, which may have missing or incorrect locales (in Cygwin
or ActiveState Perl, respectively) - turning off {Site}{LocaleRegexes} is
recommended unless you know your version of Perl has working locale support.
HERE
                  );
    }

    # Warn against Perl 5.6 or lower for UTF-8
    if ( $perlvernum < 5.008 ) {
        $n .= WARN("Perl 5.8 is required if you are using TWiki's",
                   "experimental UTF-8 support\n");
    }

    # Check for 'useperlio' in Config on Perl 5.8 or higher - required
    # for use of ':utf8' layer.
    if ( $perlvernum >= 5.008 and 
         not ( exists $Config::Config{useperlio} and
               $Config::Config{useperlio} eq 'define' ) ) {
        $n .= WARN(<<HERE
This version of Perl was not compiled to use PerlIO by default ('useperlio'
not set in Config.pm, see <i>Perl's Unicode Model</i> in 'perldoc
perluniintro') - re-compilation of Perl will be required before it can be
used to enable TWiki's experimental UTF-8 support.
HERE
                  );
    }

    # Check for d_setlocale in Config (same as 'perl -V:d_setlocale')
    eval "use Config";
    if ( !( exists $Config::Config{d_setlocale} &&
            $Config::Config{d_setlocale} eq 'define' ) ) {
        $n .= WARN(<<HERE
This version of Perl was not compiled with locale support ('d_setlocale' not
set in Config.pm) - re-compilation of Perl will be required before it can be
used to support TWiki internationalisation.
HERE
                  );
    }
    return $n;
}

sub _CHECKVAR_Site_CharSet {
    # Extract the character set from locale and use in HTML templates
    # and HTTP headers
    unless( defined $TWiki::cfg{Site}{CharSet} ) {
        $TWiki::cfg{Site}{Locale} =~ m/\.([a-z0-9_-]+)$/i;
        $TWiki::cfg{Site}{CharSet} = $1 if defined $1;
        $TWiki::cfg{Site}{CharSet} =~ s/^utf8$/utf-8/i;
        $TWiki::cfg{Site}{CharSet} =~ s/^eucjp$/euc-jp/i;
        $TWiki::cfg{Site}{CharSet} = lc $TWiki::cfg{Site}{CharSet};
    }
    return '';
}

sub _CHECKVAR_UpperNational {
    if( $perlvernum < $perlVerPreferred || 1) {
        # Locales are off/broken, or using pre-5.6 Perl, so have to 
        # explicitly list the accented characters (but not if using UTF-8)
        my $forUpperNat = join '', grep { uc($_) ne $_ and m/[^a-z]/ } map { chr($_) } 1..255;

        if ($forUpperNat) {
            return WARN( <<HERE
The following upper case accented characters have been found in this locale
and should be considered for use in this parameter:
<strong>$forUpperNat</strong>
HERE
                       );
        }
    }
    return '';
}

sub _CHECKVAR_LowerNational {
    if( $perlvernum < $perlVerPreferred || 1) {
        # Locales are off/broken, or using pre-5.6 Perl, so have to 
        # explicitly list the accented characters (but not if using UTF-8)
        my $forLowerNat = join '', grep { uc($_) ne $_ and m/[^a-z]/ } map { chr($_) } 1..255;

        if ($forLowerNat) {
            return WARN( <<HERE
The following lower case accented characters have been found in this locale
and should be considered for use in this parameter:
<strong>$forLowerNat</strong>
HERE
                       );
        }
    }
    return '';
}

sub _CHECKVAR_Site_Locale {
    my $e = '';
    my $locale = $TWiki::cfg{Site}{Locale};
    setlocale(&LC_CTYPE, $locale);
    my $currentLocale = setlocale(&LC_CTYPE);
    if ( $currentLocale ne $locale ) {
        $e .= WARN(<<HERE
Unable to set locale to '$locale'. The actual locale is '$currentLocale'
- please test your locale settings. This warning can be ignored if you are
not planning to use locales (e.g. your site uses English only) - or you can
set  {Site}{Locale} to <code>C</code>, which should always work.
HERE
                   );
    }
    if( $locale !~ /[a-z]/i && $TWiki::cfg{UseLocale} ) {
        $e = WARN(<<HERE
UseLocale set but {Site}{Locale} '$locale' has no alphabetic characters
HERE
                 );
    }

    # Set the default site charset
    unless( defined( $TWiki::cfg{Site}{CharSet}) ) {
        $TWiki::cfg{Site}{CharSet} = 'iso-8859-15';
    }

    # Extract the default site language - ignores '@euro' part of
    # 'fr_BE@euro'-type locales.
    unless( defined( $TWiki::cfg{Site}{Lang} )) {
        $TWiki::cfg{Site}{Locale} =~ m/^([a-z]+)_([a-z]+)/i;
        $TWiki::cfg{Site}{Lang} = (lc $1) if defined $1;
    }

    unless( defined( $TWiki::cfg{Site}{FullLang} )) {
        $TWiki::cfg{Site}{Locale} =~ m/^([a-z]+)_([a-z]+)/i;
        $TWiki::cfg{Site}{FullLang} = (lc "$1-$2" )
          if defined $1 and defined $2;
    }

    # Check for unusable multi-byte encodings as site character set
    # - anything that enables a single ASCII character such as '[' to be
    # matched within a multi-byte character cannot be used for TWiki.
    # Refuse to work with character sets that allow TWiki syntax
    # to be recognised within multi-byte characters.
    # FIXME: match other problematic multi-byte character sets
    if( $TWiki::cfg{UseLocale} &&
        $TWiki::cfg{Site}{CharSet} =~
        m/^(?:iso-?2022-?|hz-?|gb2312|gbk|gb18030|.*big5|.*shift_?jis|ms.kanji|johab|uhc)/i ) {

        $e .= ERROR(<<HERE
Cannot use this multi-byte encoding ('$TWiki::cfg{Site}{CharSet}') as site character
encoding. Please set a different character encoding in the {Site}{Locale}
setting.
HERE
                   );
    }

    return $e;
}

sub _CHECKVAR_ScriptSuffix {
    # SMELL: should check to see what the extension on _this_ script
    # is, and generate a helpful message
    if ( defined $TWiki::cfg{ScriptSuffix} && $TWiki::cfg{ScriptSuffix} ne '' ) {
    if ( ! $query->path_info() =~ /$TWiki::cfg{ScriptSuffix}$/ ) {
        return ERROR('this script ('.$query->pather_info().') called with different ScriptSuffix setting'.$TWiki::cfg{ScriptSuffix});
    }
    }
    return '';
}

sub _CHECKVAR_RCS_EgrepCmd { return _checkGnuProgram($TWiki::cfg{RCS}{EgrepCmd}); }
sub _CHECKVAR_RCS_FgrepCmd { return _checkGnuProgram($TWiki::cfg{RCS}{FgrepCmd}); }
sub _CHECKVAR_RCS_initTextCmd { return _checkRCSProgram('initTextCmd'); }
sub _CHECKVAR_RCS_initBinaryCmd { return _checkRCSProgram('initBinaryCmd'); }
sub _CHECKVAR_RCS_tmpBinaryCmd { return _checkRCSProgram('tmpBinaryCmd'); }
sub _CHECKVAR_RCS_ciCmd { return _checkRCSProgram('ciCmd'); }
sub _CHECKVAR_RCS_ciDateCmd { return _checkRCSProgram('ciDateCmd'); }
sub _CHECKVAR_RCS_coCmd { return _checkRCSProgram('coCmd'); }
sub _CHECKVAR_RCS_histCmd { return _checkRCSProgram('histCmd'); }
sub _CHECKVAR_RCS_infoCmd { return _checkRCSProgram('infoCmd'); }
sub _CHECKVAR_RCS_rlogDateCmd { return _checkRCSProgram('rlogDateCmd'); }
sub _CHECKVAR_RCS_diffCmd { return _checkRCSProgram('diffCmd'); }
sub _CHECKVAR_RCS_lockCmd { return _checkRCSProgram('lockCmd'); }
sub _CHECKVAR_RCS_unlockCmd { return _checkRCSProgram('unlockCmd'); }
sub _CHECKVAR_RCS_delRevCmd { return _checkRCSProgram('delRevCmd'); }

sub _CHECKVAR_StoreImpl {
    my $mess = '';
    if( $TWiki::cfg{StoreImpl} eq 'RcsWrap') {
        # Check that GNU diff is found in PATH; used by rcsdiff
        $mess .= NOTE( "Note: The 'diff' program found on the path is used by RcsWrap to compare revisions ".
                         _checkGnuProgram( "diff"));
    }

    return $mess;
};

sub _CHECKVAR_UseClientSessions {
    my $mess = '';
    if (!eval "use CGI::Cookie; 1") {
        $mess .= <<HERE;
The CGI::Cookie Perl module is required for session support, but is not
available.
HERE
    }
    if (!eval "use CGI::Session; 1") {
        $mess .= <<HERE;
The CGI::Session Perl module is required for session support, but is not
available.
HERE
    }
    if( $mess ) {
        if ($TWiki::cfg{UseClientSessions} ) {
            $mess = ERROR( $mess );
        } else {
            $mess = WARN( $mess );
        }
    }
    return $mess;
}

sub _CHECKVAR_AuthScripts {
    if( $TWiki::cfg{AuthScripts} ) {
        if( $TWiki::cfg{LoginManager} eq "TWiki::Client::NoLogin" ) {
            return WARN("
You've asked that some scripts require authentication, but haven't
specified a way for users to log in. Please pick a LoginManager
(above) other than NoLogin.
                     ");
        }
    }
    return '';
}

# Generates the appropriate HTML for getting a value to configure the
# entry. The opts are additional parameters, and by convention may
# be a number (for a string length), a comma separated list of values
# (for a select) and may also have an M for mandatory. The actual
# input field is decided by the type, which is used to compose a function
# name by prepending _PROMPT_FOR_.
#.
# The method also builds a function name by prepending _CHECK_VAR_ to the
# field name, and calls it if it exists to perform additional checking
# for that specific field (see _CHECK_VAR_DataDir as an example)
#
sub _checkAndBuildValueGrabber {
    my( $type, $opts, $desc, $keys) = @_;
    my $output = '';
    my $mandatory = ($opts =~ /\sM\s/);
    # field id
    my $id = $keys;
    $output .= CGI::hidden( 'TYPEOF:'.$id, $type ). "\n";

    my $checker = '_CHECKVAR_'.$id;
    $checker =~ s/}{/_/g;
    $checker =~ s/[}{]//g;
    if( defined &$checker ) {
        no strict 'refs';
        my $check = &$checker();
        die "$checker" unless defined $check;
        $desc .= $check;
        use strict 'refs';
    }

    my $prompter = '_PROMPT_FOR_'.$type;
    my $value = eval '$TWiki::cfg'.$keys;
    no strict 'refs';
    $prompter = &$prompter($id, $opts, $value, $keys, $mandatory);
    my $class = $type;
    $class .= ' mandatory' if $mandatory;
    $prompter = CGI::span({class=>$class}, $prompter) if $mandatory;
    use strict 'refs';

    $keys = CGI::span({class=>'mandatory'}, $keys) if $mandatory;
    my $hidden = 0;
    if (length($desc) == 0 || $desc =~ /\A\s\Z/) { 
        $hidden = 1;
    }
    return _docBlock( $output.$desc, $hidden )._setting( $keys, $prompter );
}

sub _showPlugins {
    my %modules;
    foreach my $libDir ( @INC ) {
        if( opendir( DIR, "$libDir/TWiki/Plugins" ) ) {
            foreach my $file ( grep { /^[A-Za-z0-9_]+Plugin\.pm$/ }
                                 readdir DIR ) {
                my $module = $file;
                $module =~ s/\.pm$//;
                $TWiki::cfg{Plugins}{$module}{Enabled} ||= 0;
                $module =~ /^(.*)$/;    # untaint
                $module = $1;
                # only add the first instance of any plugin, as only
                # the first can get loaded from @INC.
                unless( $modules{$module} ) {
                    $modules{$module} =  $libDir;
                }
                closedir( DIR );
            }
        }
    }
    my $block = '';
    foreach my $m ( sort keys %modules ) {
        $block .= _checkAndBuildValueGrabber
          ( 'BOOLEAN', '', 
#SMELL - i'm assuming that the Plugin topic is in the SystemWeb :(
"<a rel=\"nofollow\" href=\"$TWiki::cfg{ScriptUrlPath}/view$TWiki::cfg{ScriptSuffix}/$TWiki::cfg{SystemWebName}/$m\">$m</a>",
            '{Plugins}{'.$m.'}{Enabled}'
        );
    }
    return $block;
}

sub _showLanguages {
  opendir( DIR, $TWiki::cfg{LocalesDir}) or
      return 'Couldn\'t read TWiki {LocalesDir}!';
  my $block = '';
  foreach my $file ( grep { /^.*\.po$/ } readdir DIR ) {
    $file =~ m/^(.*)\.po$/;
    my $lang = $1;
    $lang = "'$lang'" if $lang =~ /\W/;
    $block .= _checkAndBuildValueGrabber ( 'BOOLEAN', '', 'Enable the language <strong>' . $lang . '</strong>', '{Languages}{' . $lang . '}{Enabled}' );
  }
  closedir( DIR );
  return $block;
}

########################################################################
##################### WRITING NEW VALUES ###############################
########################################################################

sub setConfig {
    my ($path, $updates) = @_;
    my $txt = '';
    if( open(F, "<$path")) {
        undef $/;
        $txt = <F>;
        close(F);
    }

    $txt =~ s/^\s*1;\s*$//gm;

    open(F, ">$path") ||
      die "Failed to open $path for write";

    foreach my $config ( keys %$updates ) {
        # kill the old settings if any are there
        $txt =~ s/\$TWiki::cfg$config\s*=.*?;\s*\n//s;
        $txt .= '$TWiki::cfg'.$config.' = '.$updates->{$config}.";\n";
    }
    print F $txt,"1;\n";
    close(F);

    if( defined( $TWiki::cfg{ConfigurationLogName} ) &&
        open(F, '>>'.$TWiki::cfg{ConfigurationLogName} )) {
        my $date = gmtime();
        my $user = $query->remote_user() || 'guest';
        foreach my $config ( keys %$updates ) {
            print F '| ',$date,' | ',$user,' | ',$config,' | ',
              $updates->{$config}," |\n";
        }
        close(F);
    }
}

# Convert value to a canonical perl representation suitable for writing
# to LocalSite.cfg
sub _perlifyType {
    my ($val,$type) = @_;

    if ($type eq 'BOOLEAN') {
        return ($val ? 1 : 0);
    } elsif ($type eq 'NUMBER') {
        $val ||= 0;
        return 0+$val;
    } elsif ($type eq 'OCTAL') {
        $val ||= 0;
        $val = '0'.$val unless $val =~ /^0/;
        return $val;
    } else {
        $val ||= '';
        $val =~ s/'/\\'/g;
        return "'".$val."'";
    }
}

sub _perlModulesCheck {
    my $mods = shift;
    my $e = '';
    foreach my $mod (keys %$mods) {
        my $n = '';
        eval "use $mod";
        if ($@) {
            $n = WARN('not installed. May be required for ',
                      $mods->{$mod});
        } else {
            my $mod_version;
            no strict 'refs';
            eval '$mod_version = ${'.$mod.'::VERSION}';
            use strict 'refs';
            $n = $mod_version || 'unknown';
        }
        $e .= _setting($mod, $n);
    }
    return $e;
}

########################################################################
#################### MAIN ACTION ENTRY POINTS ##########################
########################################################################

sub _serveImage {
    my($type, $image )= @_;

    print "Content-type: $type\n\n";
    if( open(F, "logos/$image")) {
        local $/ = undef;
        print <F>;
        close(F);
    }
}

sub handleUpdate {
    my $path = shift;
    my $pass = $query->param( 'cfgAccess' );
    my $param;
    my $output = '';
    unless( defined( $pass )) {
        $output .= CGI::start_form({ action=>$ENV{SCRIPT_NAME}, method=>"post" });
        # Pass all URL params through
        foreach $param ( $query->param ) {
            $output .= CGI::hidden( $param, $query->param( $param ));
            $output .= "\n";
        }

        my $changed = calculateChanges();
        my $itemText = ($changed == 1) ? 'item' : 'items';
        $output .= CGI::div({ class => 'explanation'},
                            CGI::strong( 'Changing ' . $changed.
                                           ' configuration ' . $itemText.
                                             '.').
                  (($changed == 0) ? CGI::br() .
                     CGI::a( { href=>$url.'?t='.time(),
                               rel => 'nofollow' },
                             'Return to configuration') : CGI::br() .
               'Proceed with the steps below to save your changes.'));

        # and add a few more
        $output .= CGI::h2('Enter the configuration password');
        if ($TWiki::cfg{Password} ne '') {
        	$output .= CGI::p(CGI::strong("Your Password:").CGI::br());
            $output .= CGI::password_field( 'cfgAccess', '', 20, 80 );
            $output .= '&nbsp;' . CGI::submit(-class=>'twikiSubmit', -value=>'Save changes');
            $output .= CGI::br();
        } else {
			$output .= CGI::hidden( 'cfgAccess', '' );
        }
        my $forgotPassword = '';
        if ($TWiki::cfg{Password} ne '') {
            $forgotPassword = CGI::strong("Forgot your password?"). CGI::br(). 'To reset the password, log in to the server and delete the <code>$TWiki::cfg{Password} = \'...\';</code> line in <code>lib/LocalSite.cfg</code><p />';
        }
        $output .= CGI::div({ class => 'explanation'},
                            CGI::span( $forgotPassword . CGI::img({src=>$ENV{SCRIPT_NAME}.'?action=image;image=warning.gif;type=image/gif', alt=>''}) . '&nbsp;' . <<'HERE'
<span class="twikiAlert"><b>Notes on Security</b></span>:
<ul>
    <li>If you don't set a password, or the password is cracked, then <code>configure</code> could be used to do <strong>very</strong> nasty things to your server.</li>
    <li>If you are running TWiki on a public website, you are <strong>strongly</strong> advised to disable saving from <code>configure</code> by making <code>lib/LocalSite.cfg</code> readonly once you are happy with your configuration.</li>
</ul>
HERE
                         ));
		if ($TWiki::cfg{Password} ne '') {
        	$output .= CGI::p( "You may change your password here:" );
		}

        $output .= CGI::div({ class => 'formElem'},
        
                            CGI::strong("New Password:").
                            CGI::br().
                            CGI::password_field( 'newCfgP', '', 20, 80 ).
                            CGI::br().
                            CGI::strong("Confirm Password:").CGI::br().
                            CGI::password_field( 'confCfgP', '', 20, 80 ).
                            CGI::br().
                            CGI::submit(-class=>'twikiSubmit', -value=>'Set Password and Save changes'));
        $output .= CGI::end_form();
        $output .= CGI::end_html();
        return $output;
    }

    unless( crypt( $pass, $TWiki::cfg{Password}) eq
            $TWiki::cfg{Password} || $TWiki::cfg{Password} eq '') {
        $output .= CGI::span( {class => 'error' }, "Incorrect password" ).
          CGI::end_html();
        return $output;
    }

    my $changed = 0;
    my %updates;

    if( $query->param( 'newCfgP' )) {
        if( $query->param( 'newCfgP' ) eq
                $query->param( 'confCfgP' )) {
            my @saltchars = ( 'a'..'z', 'A'..'Z', '0'..'9', '.', '/' );
            my $salt = $saltchars[int(rand($#saltchars+1))] .
              $saltchars[int(rand($#saltchars+1)) ];
            $updates{'{Password}'} =
              _perlifyType(
                           crypt( $query->param( 'newCfgP' ), $salt ),
                           'STRING' );
            $changed++;
            $output .= "Password changed";
        } else {
            $output .= "New password and confirmation do not match";
            return $output;
        }
    }

    $output .= CGI::h2('Updating configuration');
    foreach $param ( $query->param ) {
        next unless $param =~ /^^TYPEOF:(.*)/;
        my $type = $query->param( $param );
        $param =~ s/^TYPEOF:(.*)$/$1/;
        my $basevar = $1;
        my $var = '$TWiki::cfg'.$basevar;
        my $val = $query->param( $param );
        my $def;
        eval "\$def = defined( $var );";
        if( $type ) {
            eval "\$def = $var;" if $def;
            next if( $type eq 'OCTAL' && sprintf('0%o', $def) =~ /^0*$val$/ );
            next if( $type eq 'NUMBER' && $val + 1 == $def + 1 );
            next if( $type eq 'BOOLEAN' && ($val && $def || !$val && !$def));
            next if( $val eq $def );
            $output .= CGI::h3($var).
              CGI::b('old ').
              CGI::code($def||' ').
              CGI::br().
              CGI::b('new ').
              CGI::code($val||' ');
            $updates{$basevar} = _perlifyType($val, $type);
            $changed++;
        }
    }
    $output .= CGI::p();
    setConfig($path, \%updates);
    my $itemText = ($changed == 1) ? 'item' : 'items';
    $output .= CGI::hr();
    $output .= CGI::p(CGI::strong($changed.' configuration ' . $itemText . ' changed. '));
    $output .= CGI::p(CGI::a({ rel => 'nofollow',
                               href=>$url.'?t='.time() },
                             'Return to configuration'));
    return $output;
}

sub calculateChanges {
    my $param;
    my $changed = 0;
    foreach $param ( $query->param ) {
        next unless $param =~ /^^TYPEOF:(.*)/;
        my $type = $query->param( $param );
        $param =~ s/^TYPEOF:(.*$)/$1/;
        my $var = '$TWiki::cfg'.$1;
        my $val = $query->param( $param );
        my $def;
        eval "\$def = defined( $var );";
        if( $type ) {
            eval "\$def = $var;" if $def;
            next if( $type eq 'OCTAL' && sprintf('0%o', $def) =~ /^0*$val$/ );
            next if( $type eq 'NUMBER' && $val + 1 == $def + 1 );
            next if( $type eq 'BOOLEAN' && ($val && $def || !$val && !$def));
            next if( $val eq $def );
            $changed++;
        }
    }
    return $changed;
}

sub performSanityChecks {
    my( $brokenTWikiCfgError, $brokenLocalSiteError ) = @_;
    my $output = '';

    if ($brokenTWikiCfgError) {
        $output .= CGI::h2('WARNING:').
          CGI::p('TWiki.cfg is unreadable or has a configuration problem that is causing a Perl error - the following message(s) should help locate the problem.');
        $output .= $brokenTWikiCfgError;

        # EARLY EXIT
        $output .= CGI::end_html();
        return $output;
    }

    if ($brokenLocalSiteError) {
        $output .= CGI::h2('WARNING:').
          ERROR('LocalSite.cfg is unreadable or has a configuration problem that is causing a Perl error - the following message(s) was generated:').
          CGI::pre($brokenLocalSiteError).
          'The @INC path is '.
          CGI::pre(join(":", @INC)).
          NOTE('This may be because this is the first time you have run configure. In this case you can simply ignore this error until you have filled in your <a rel="nofollow" href="#" onclick="foldBlock(\'GeneralPathSettings\'); return false;">General path settings</a>. Otherwise, check that the file exists, and the webserver user is allowed to read it.');
    }

    # Check whether basic CGI modules exist (some broken installations of
    # Perl don't have this, even though they are standard modules), and warn user
    my $modMissing = 0;
    foreach my $mod (keys %$basicMods) {
        eval "use $mod";
        if ($@) {
            unless ($modMissing) {
                $output .= ERROR( 'Perl Module(s) missing');
            }
            $modMissing = 1;
            $output .= ERROR( 'Essential Perl Module \'',$mod,
                         '\' not installed - please check the setting ',
                         'of @INC.' );
        }
    }

    # If any critical modules missing, display @INC and give up 
    if ($modMissing) {
        $output .= NOTE( '@INC = ', join( ' ', @INC ));
        return $output;
    }

    return $output;
}

sub presentReadOnlyInfo {
    # use strict;        # Recommended for mod_perl, enable for Perl 5.6.1 only
    # Doesn't work well here, due to 'do "TWiki.cfg"'
    # use diagnostics;    # Debug only

    # Load CGI modules (run-time, after checking they are accessible)
    require CGI;
    import CGI qw( -any );
    require CGI::Carp;
    import CGI::Carp qw( fatalsToBrowser );

    $errors = 0;
    $warnings = 0;

    my $output = '';
    my $block = '';
    for my $key ( sort keys %ENV ) {
        $block .= _setting($key, $ENV{$key});
    }
    $output .= _foldableBlock(CGI::em( 'Environment variables' ),
                              '(read only) ', $block);

    $block = '';

    # Make %ENV safer for CGI (should reflect TWiki.pm)
    my $originalPath = $ENV{PATH} || '';
    if( $TWiki::cfg{SafeEnvPath} ) {
        # SMELL: this untaint probably isn't needed
        my $ut = $TWiki::cfg{SafeEnvPath};
        $ut =~ /^(.*)$/;
        $ENV{PATH} = $1;
    }
    delete @ENV{ qw( IFS CDPATH ENV BASH_ENV ) };
    my $perlverMsg = $perlver;        # Default version message

    # Load Config module - used here and elsewhere
    require Config;

    # Set $TWiki::cfg{DetailedOS} if not using later versions of TWiki.cfg for BeijingRelease
    # - this code enables the latest testenv to be used with Dec 2001 and 
    # earlier releases.
    if ( !defined $TWiki::cfg{DetailedOS} ) {
        $TWiki::cfg{DetailedOS} = $Config::Config{'osname'};
    }

    # Detect Perl flavour on Windows, and Cygwin Perl/RCS package versions

    if ($TWiki::cfg{DetailedOS} eq 'cygwin') {
        $perltype = 'Cygwin';                # Cygwin Perl only
        my ($pkg, $pkgName);

        # Get Cygwin perl's package version number
        $pkgName = 'perl';
        $pkg = `/bin/cygcheck -c $pkgName | /bin/grep $pkgName 2>/dev/null`; 
        if ($?) { 
            $pkg = " [Cannot identify package - cygcheck or grep not installed]";
            $perlverMsg = $perlver . $pkg
        } else {
            $pkg = (split ' ', $pkg)[1];    # Package version
            $perlverMsg = $pkg;
        }

        # Get Cygwin RCS's package version number
        $pkgName = 'rcs';
        $pkg = `/bin/cygcheck -c $pkgName | /bin/grep $pkgName 2>/dev/null`; 
        if ($?) { 
            $pkg = " [Cannot identify package - cygcheck or grep not installed]";
            $cygwinRcsVerNum = $pkg;    
        } else {
            $pkg = (split ' ', $pkg)[1];    # Package version
            $cygwinRcsVerNum = $pkg;    
        }
    } elsif ($TWiki::cfg{DetailedOS} =~ /win/i && $TWiki::cfg{DetailedOS} !~ /darwin/i ) {
        # Windows Perl - try ActivePerl-only function: returns number if
        # successful, otherwise treated as a literal (bareword).
        my $isActivePerl= eval 'Win32::BuildNumber !~ /Win32/';
        if( $isActivePerl ) {
            $perltype = 'ActiveState';
            $perlverMsg = $perlver . ", build " . Win32::BuildNumber();
        } else {
            # Could be SiePerl or some other Win32 port of Perl
            $perltype = 'SiePerl or other Windows Perl';
        }
    } else {
        $perltype = 'generic';
    }

    # Detect executable name suffix, e.g. .exe on Windows or '' on Unix
    # Avoid testing for .exe suffixes on Cygwin, since the built-in
    # grep and ls don't end in '.exe', even though Perl's '_exe' setting
    # indicates they should.
    my $exeSuffix='';
    if ( $Config::Config{'_exe'} and ($TWiki::cfg{OS} eq 'WINDOWS' and $perltype ne 'Cygwin') ) { 
        if ( ! $ENV{INTERIX_ROOT} ) { #this is set is we are using UnixServicesForWindows (or INTERIX funnily enough) and they don't use .exe either
            $exeSuffix = $Config::Config{'_exe'};
        }
    }

    # Detect whether mod_perl was loaded into Apache
    my $modPerlLoaded = ( exists $ENV{SERVER_SOFTWARE} && 
                          ( $ENV{SERVER_SOFTWARE} =~ /mod_perl/ ));
    # Detect whether we are actually running under mod_perl
    # - test for MOD_PERL alone, which is enough.
    my $usingModPerl = ( exists $ENV{MOD_PERL} );
    my $modPerlVersion;

    # Get the version of mod_perl if it's being used
    if ( $usingModPerl ) {
        $modPerlVersion = eval 'use mod_perl; return $mod_perl::VERSION';
        $block .= _setting('',
                           WARN(<<HERE
You are running <tt>configure</tt> with <tt>mod_perl</tt>. This
is risky because mod_perl will remember old values of configuration
variables. You are *highly* recommended not to run configure under
mod_perl (though the rest of TWiki can be run with mod_perl, of course)
HERE
                               ));
    }

    my $n = ucfirst(lc($TWiki::cfg{OS}));
    $n .= " ($TWiki::cfg{DetailedOS})" if ( $TWiki::cfg{DetailedOS} ne '' );
    # OS
    $block .= _setting("Operating system", $n);

    # Perl version and type
    $perlverMsg .= " ($perltype)" if $perltype ne 'generic';
    $block .= _setting("Perl version", $perlverMsg);

    if ( $perlvernum < $perlverRequired ) {
        $block .= _setting('',
                           WARN(<<HERE
This version of Perl is too old for use with TWiki -
upgrade to at least Perl $perlverRequiredString
and preferably to Perl $perlverRecommended.
HERE
                               ));
    }

    # Perl @INC (lib path)
    $block .= _setting('@INC library path', join(CGI::br(), @INC ),
                       NOTE(<<HERE
This is the Perl library path, used to load TWiki modules,
third-party modules used by some plugins, and Perl built-in modules.
HERE
                           ));

    $block .= _setting('CGI bin directory', _checkBinDir());

    # Turn off fatalsToBrowser while checking module loads, to avoid load errors in
    # browser in some environments.  
    $CGI::Carp::WRAP = $CGI::Carp::WRAP = 0;    # Avoid warnings...

    # Add to list of required modules if non-Unix, or MacOS X (detected by
    # Perl as 'Darwin') - $TWiki::cfg{DetailedOS} is set in TWiki.cfg.
    $TWiki::cfg{DetailedOS} ||= $TWiki::cfg{DetailedOS};

    # Check that the TWiki.pm module can be found
    eval "require TWiki";
    my $twikiFound = 0;
    my $mess = '';
    if ($@) {
        $mess = $@;
        $mess = ERROR("'TWiki.pm' could not be loaded. The error was:").
                CGI::pre($mess).
                ERROR("Check path to <code>twiki/lib</code> and check that LocalSite.cfg is present and readable");
    } else {
        $twikiFound = 1;
        my $mod_version = eval '$TWiki::wikiversion || $TWiki::VERSION';
        $mod_version ||= 'unknown';
        $mess = 'OK, TWiki.pm found (Version: <strong>'.$mod_version.'</strong>)';
    }
    $block .= _setting('TWiki module in @INC path', $mess);

    #add in the basic Modules so that we list their versions in the UI
    map { $requiredMods->{$_} = $basicMods->{$_} }
       keys %$basicMods;

    if ( defined $TWiki::cfg{DetailedOS} and ($TWiki::cfg{DetailedOS} =~ /darwin/i or $TWiki::cfg{OS} ne 'UNIX') ) {
        map { $requiredMods->{$_} = $requiredModsNonUnix->{$_} }
          keys %$requiredModsNonUnix;
    } else {
        # these are optional on Unix
        map { $optionalMods->{$_} = $requiredModsNonUnix->{$_} }
          keys %$requiredModsNonUnix;
    }

    # Check that each of the required Perl modules can be loaded, and
    # print its version number.
    my $set = '';
    foreach my $mod (keys %$requiredMods) {
        eval "use $mod";
        if ($@) {
            $set .= _setting($mod, ERROR("not installed. Required for ",
                                         $requiredMods->{$mod}));
        } else {
            my $mod_version;
            no strict 'refs';
            eval '$mod_version = ${'.$mod.'::VERSION}';
            use strict 'refs';
            $n = $mod_version || 'unknown';
            # Check for potential CGI.pm module upgrade 
            if( $mod eq 'CGI' and $mod_version < $cgiModVerRecommended ) {
                if ( $perltype eq 'Cygwin' and $perlver eq '5.8.0' ) {
                    # Recommend CGI.pm upgrade if using Cygwin Perl 5.8.0 
                    $n .= WARN( "CGI.pm version $cgiModVerRecommended or higher",
                                "is recommended to avoid problems with attachment",
                                "uploads on Cygwin Perl $perlver.");
                } elsif ( $usingModPerl and $modPerlVersion >= 1.99 ) {
                    # Recommend CGI.pm upgrade if using mod_perl 2.0, which
                    # is reported as version 1.99 and implies Apache 2.0
                    $n .= WARN("CGI.pm version $cgiModVerRecommended or higher is",
                               "recommended to avoid problems with mod_perl version",
                               "$modPerlVersion on Apache 2.0 or higher.");
                }
            }
            $set .= _setting( $mod, $n );
        }
    }
    $block .= _setting("Required Perl modules",
                       CGI::start_table({width=>'100%'}).
                       $set.CGI::end_table());

    # Check that each of the optional Perl modules can be loaded, and
    # print its version number.
    $set = _perlModulesCheck( $optionalMods );
    $set .= _perlModulesCheck( $I18Mods );
    $set .= _perlModulesCheck( $] >= 5.008 ? $I18Mods_perl58 : $I18Mods_perl56 );
    $block .= _setting("Optional Perl Modules",
                       CGI::start_table({width=>'100%'}).
                       $set.CGI::end_table());

    # All module checks done, OK to enable fatalsToBrowser
    import CGI::Carp qw( fatalsToBrowser );

    # PATH_INFO
    $block .= _setting(CGI::a({name=>'PATH_INFO'},'PATH_INFO'), $query->path_info().
              NOTE(<<HERE
For a URL such as <strong>$url/foo/bar</strong>,
the correct PATH_INFO is <strong>/foo/bar</strong>, without any prefixed path
components. <a rel="nofollow" href="$url/foo/bar#PATH_INFO">
<strong>Click here to test this</strong></a>
- particularly if you are using mod_perl, Apache or IIS, or are using
a web hosting provider.
Look at the new path info here. It should be <strong>/foo/bar</strong>.
HERE
                  ));

    # mod_perl
    if( $usingModPerl ) {
        $n = "Used for this script";
    } else {
        $n = "Not used for this script";
    }
    $n .= NOTE( 'mod_perl is ', $modPerlLoaded ? '' : 'not',
                ' loaded into Apache' );
    if ( $modPerlVersion ) {
        $n .= NOTE( 'mod_perl version ', $modPerlVersion );
    }

    # Check for a broken version of mod_perl 2.0
    if ( $usingModPerl && $modPerlVersion =~ /1\.99_?11/ ) {
        # Recommend mod_perl upgrade if using a mod_perl 2.0 version
        # with PATH_INFO bug (see Support.RegistryCookerBadFileDescriptor
        # and Bugs:Item82)
        $n .= ERROR(<<HERE
Version $modPerlVersion of mod_perl is known to have major bugs that prevent
its use with TWiki. $modPerlVersionRecommended or higher is recommended, or
you could always use SpeedyCGI.
HERE
                   );
    }
    $block .= _setting('mod_perl', $n);

    # Get web server's user and group info
    my $usr = "";
    my $grp = "";
    if( $TWiki::cfg{OS} eq 'UNIX' or  ($TWiki::cfg{OS} eq 'WINDOWS' and $perltype eq 'Cygwin' ) ) {
        $usr = lc( getpwuid($>) );        # Unix/Cygwin Perl - effective UID
        $grp = join(',', map { lc(getgrgid( $_ )) } split( " ", $( ) );
    } else {                # ActiveState or other Win32 Perl
        $usr = lc( getlogin );
        # Try to use Cygwin's 'id' command - may be on the path, since Cygwin
        # is probably installed to supply ls, egrep, etc - if it isn't, give up.
        # Run command without stderr output, to avoid CGI giving error.
        # Get names of primary and other groups.
        $grp = lc(qx(sh -c '( id -un ; id -gn) 2>/dev/null' 2>nul ));
        if ($?) { 
            $grp = "[Cannot identify groups - no Cygwin 'id' or 'sh' command on path]";
        }
    }

    $block .= _setting('CGI user', 'userid = <strong>'.$usr.'</strong> groups = <strong>'.
              $grp.'</strong>'.
              NOTE('Your CGI scripts are executing as this user.'));

    $block .= _setting("Original PATH", $originalPath.
              NOTE(<<HERE
This is the PATH value passed in from the web server to this
script - it is reset by TWiki scripts to the PATH below, and
is provided here for comparison purposes only.
HERE
                  ));

    my $currentPath = $ENV{PATH} || '';     # As re-set earlier in this routine
    $block .= _setting("Current PATH", $currentPath,
              NOTE(<<HERE
This is the actual PATH setting that will be used by Perl to run
programs. It is normally identical to {SafeEnvPath}, unless
that variable is empty, in which case this will be the webserver users
standard path..
HERE
                  ));

    # Check that GNU patch is found in PATH 
    $block .= _setting(
        "patch", _checkGnuProgram( "patch" ).
          NOTE('It is used by the UpgradeTwiki script to upgrade an existing TWiki installation' ));

    # PERL5SHELL check for non-Cygwin Perl on Windows only
    if( $TWiki::cfg{OS} eq 'WINDOWS' && $perltype ne 'Cygwin' ) {

        # ActiveState or SiePerl/other
        # FIXME: Advice in this section should be reviewed and tested by people
        # using ActivePerl
        my $perl5shell = $ENV{PERL5SHELL} || '';
        $n = $perl5shell.
          NOTE(<<HERE
This environment variable is used by ActiveState and other Win32 Perls to run
commands from TWiki scripts - it determines which shell program is used to run
commands that use 'pipes'.  Examples of shell programs are cmd.exe,
command.com (aka 'DOS Prompt'), and Cygwin's 'bash'
(<strong>recommended</strong> if Cygwin is installed).
<p>
To use 'bash' with ActiveState or other Win32 Perl you should set the
PERL5SHELL environment variable to something like
<tt><strong>c:/YOURCYGWINDIR/bin/bash.exe -c</strong></tt>
This should be set in the System Environment, and ideally set directly in the
web server (e.g. using the Apache <tt>SetEnv</tt> directive).
HERE
              );
        if( $perltype eq 'ActiveState' ) {
            $n .= WARN(<<HERE
ActiveState Perl on IIS does not support safe pipes, which is the mechanism used by TWiki to prevent a range
of attacks aimed at arbitrary command execution on the server. You are <b>highly</b> recommended not to use this
particular configuration on a public server (one exposed to the internet)
HERE
                      );
            if( Win32::BuildNumber() < $ActivePerlRecommendedBuild ) {
                $n .= WARN(<<HERE
ActiveState Perl must be upgraded to build <strong>
$ActivePerlRecommendedBuild
if you are going to use PERL5SHELL, which was broken in earlier builds.
HERE
                             );
            }
        }
        $block .= _setting("PERL5SHELL", $n);
    };
    $output .= _foldableBlock(CGI::em( 'CGI Setup' ), '(read only) ',
                              $block);
    return $output;
};

sub presentEditableInfo {
    # "Parse" TWiki.cfg and LocalSite.cfg
    my $output = '';
    my @blocks;
    my @heads;
    my $depth = 0;
    for my $file ( 'TWiki.cfg', 'LocalSite.cfg' ) {
        my $cfgfile = _findFileOnPath($file);
        next unless $cfgfile;
        open(F, $cfgfile) || next;
        undef $/;
        my $text = <F>;
        close(F);
        $text =~ s/^# //gm;

        my $type = '';
        my $descr;
        my $opts;
        foreach (split(/\r?\n/, $text)) {
            if( m/^\*\*([A-Z]+)(\s*.*?)\*\*/ ) {
                if( $type eq '_HELP' ) {
                    $blocks[$depth] .= _docBlock( $descr );
                }
                $type = $1;
                $opts = $2 || '';
                $opts .= ' '; # to simplify parsing
                $descr = '';
            } elsif ($type && /\$(TWiki::)?cfg(.*?)\s*=/) {
                if( $type eq '_HELP' ) {
                    $blocks[$depth] .= _docBlock( $descr );
                } else {
                    $blocks[$depth] .= _checkAndBuildValueGrabber($type, $opts, $descr, $2);
                }
                $type = '';
                $descr = '';
            } elsif( m/^#---(\++) *(.*?)$/ ) {
                my $ndepth = length($1);
                my $nhead = $2;
                while( $depth >= $ndepth ) {
                    if ($depth <= 1) {
                        $output .= _foldableBlock($heads[$depth], '', $blocks[$depth]);
                    } else {
                        $blocks[$depth - 1] .= _ordinaryBlock($depth, $heads[$depth], '', $blocks[$depth]);
                    }
                    $depth--;
                }
                $depth = $ndepth;
                $heads[$depth] = $nhead;
                $blocks[$depth] = '';
                $type = '_HELP';
            } elsif( m/^\*PLUGINS\*/ ) {
                if( $type eq '_HELP' ) {
                    $blocks[$depth] .= _docBlock( $descr );
                    $descr = '';
                }
                $blocks[$depth] .= _showPlugins();
            } elsif ( m/\*LANGUAGES\*/ ) {
                if ( $type eq '_HELP' ) {
                    $blocks[$depth] .= _docBlock( $descr );
                    $descr = '';
                }
                $blocks[$depth] .= _showLanguages();
            } elsif( $type ) {
                $descr .= "$_ ";
            }
        }
    }
    while( $depth && $blocks[$depth]) {
        if ($depth <= 1) {
            $output .= _foldableBlock($heads[$depth], '', $blocks[$depth]);
        } else {
            $blocks[ $depth - 1] .= _ordinaryBlock($depth, $heads[$depth], '', $blocks[$depth]);
        }
        $depth--;
    }
    return $output;
}

######################################################################
################# MAIN PROGRAM #######################################
######################################################################

$| = 1;                  # no buffering - FIXME: mod_perl issue?

eval "use CGI::Carp qw( fatalsToBrowser )";

use vars qw ( $setlibAvail $brokenLocalSiteError $brokenTWikiCfgError
              $js1 $css );

# Set library paths in @INC, read TWiki.cfg and set locale, at compile time
# Try to use setlib.cfg, use default path if missing
if ( -r './setlib.cfg' ) {
    require './setlib.cfg';
    $setlibAvail = 1;
} else {
    unshift @INC, '../lib';
    $setlibAvail = 0;
}

unless( $TWiki::cfg{DetailedOS} ) {
    $TWiki::cfg{DetailedOS} = $^O;
    unless( $TWiki::cfg{DetailedOS} ) {
        require Config;
        $TWiki::cfg{DetailedOS} = $Config::Config{'osname'};
    }
}
unless( $TWiki::cfg{OS} ) {
    if ($TWiki::cfg{DetailedOS} =~ /darwin/i) { # MacOS X
        $TWiki::cfg{OS} = 'UNIX';
    } elsif ($TWiki::cfg{DetailedOS} =~ /Win/i) {
        $TWiki::cfg{OS} = 'WINDOWS';
    } elsif ($TWiki::cfg{DetailedOS} =~ /vms/i) {
        $TWiki::cfg{OS} = 'VMS';
    } elsif ($TWiki::cfg{DetailedOS} =~ /bsdos/i) {
        $TWiki::cfg{OS} = 'UNIX';
    } elsif ($TWiki::cfg{DetailedOS} =~ /dos/i) {
        $TWiki::cfg{OS} = 'DOS';
    } elsif ($TWiki::cfg{DetailedOS} =~ /^MacOS$/i) { # MacOS 9 or earlier
        $TWiki::cfg{OS} = 'MACINTOSH';
    } elsif ($TWiki::cfg{DetailedOS} =~ /os2/i) {
        $TWiki::cfg{OS} = 'OS2';
    } else {
        $TWiki::cfg{OS} = 'UNIX';
    }
}

# if this fails, ignore the problem, but we have to do it
unless( eval 'do "LocalSite.cfg"' ) {
    # Capture the Perl error(s)
    $brokenLocalSiteError = 'require failed: '.
      ( $! ? $! : '') . ( $@ ? $@ : '');
}

# Read the configuration file now in order to set locale;
# includes checking for broken syntax etc.  Need 'require'
# to get the $!/$@ to work.
unless( eval 'require "TWiki.cfg" ' ) {
    # Capture the Perl error(s)
    $brokenTWikiCfgError = 'require failed: '.
      ( $! ? $! : '') . ( $@ ? $@ : '');
}

# and again
eval 'do "LocalSite.cfg"';

# Do a dynamic 'use locale' for this script
if( $TWiki::cfg{UseLocale} ) {
    require locale;
    import locale ();
}

$js1 = <<'HERE';
//<!--

var lastOpenBlock = null;
var lastOpenBlockLink = null;
var allBlocks = null; // array of all foldable blocks
var allBlockLinks = null; // array of all foldable block links (headers)

function foldBlock(id) {
    var shouldClose = false;
    var block = null;
    if (lastOpenBlock == null) {
        block = document.getElementById(id);
        if (block.open) {
            shouldClose = true;
        }
    }
    if (shouldClose) {
        closeBlock(id);
    } else {
        var o = openBlock(id);
        if (lastOpenBlock != null) {
            closeBlockElement(lastOpenBlock, lastOpenBlockLink);
        }
    }
    if (o && o.block) {
        lastOpenBlock = (lastOpenBlock == o.block) ? null : o.block;
    }
    if (o && o.blockLink) {
        lastOpenBlockLink = (lastOpenBlockLink == o.blockLink) ? null : o.blockLink;
    }
}

function openBlock(id) {
    var block = document.getElementById(id);
    var blockLink = document.getElementById('blockLink' + id);
    openBlockElement(block, blockLink);
    return {block:block, blockLink:blockLink};
}

function openBlockElement(block, blockLink) {
    block.className = 'foldableBlock foldableBlockOpen';
    block.open = true;
    blockLink.className = 'blockLink blockLinkOn';
}

function closeBlock(id) {
    var block = document.getElementById(id);
    var blockLink = document.getElementById('blockLink' + id);
    closeBlockElement(block, blockLink);
    return {block:block, blockLink:blockLink};
}

function closeBlockElement(block, blockLink) {
    block.className = 'foldableBlock foldableBlockClosed';
    block.open = false;
    blockLink.className = 'blockLink blockLinkOff';
}

function toggleAllOptions(open) {
    if (allBlocks == null) {
        allBlocks = getElementsByClassName('foldableBlock');
    }
    if (allBlockLinks == null) {
        allBlockLinks = getElementsByClassName('blockLink');
    }
    var i, ilen=allBlocks.length;
    if (open) {
        for (i=0; i<ilen; ++i) {
            openBlockElement(allBlocks[i], allBlockLinks[i]);
        }
    } else {
        for (i=0; i<ilen; ++i) {
            closeBlockElement(allBlocks[i], allBlockLinks[i]);
        }
    }
    lastOpenBlock = null;
    lastOpenBlockLink = null;
}

function getElementsByClassName(class_name)
{
    var all_obj, ret_obj = new Array();
    if (document.all)
        all_obj=document.all;
     else if (document.getElementsByTagName && !document.all)
        all_obj=document.getElementsByTagName("*");
    var len = all_obj.length;
    for (i=0;i<len;++i) {
        var myClass = all_obj[i].className;
         if (myClass == class_name) {
            ret_obj.push(all_obj[i]);
        } else {
            var classElems = myClass.split(" ");
            var elemLen = classElems.length;
            for (ii=0; ii<elemLen; ++ii) {
                if (classElems[ii] == class_name) {
                    ret_obj.push(all_obj[i]);
                }
            }    
        }
    }
    return ret_obj;
}
//-->
HERE

$css = <<'HERE';

/*    -----------------------------------------------------------
    LAYOUT
    positioning of page elements
    -----------------------------------------------------------    */

.twikiLeft {
    float:left;
    position:relative;
}
.twikiRight {
    position:relative;
    float:right;
    display:inline;
    margin:0;
    text-align:right;
}
.twikiClear {
    /* to clean up floats */
    margin:0;
    padding:0;
    height:0;
    line-height:0%;
    clear:both;
    display:block;
}
.twikiHidden {
    display:none;
}

/*    -----------------------------------------------------------
    Positioning of layout blocks
    -----------------------------------------------------------    */

.patternMiddleContainer {}
.patternLeftBar {
    position:absolute;
    left:0;
    margin:0;
    padding:0;
}

/* setting the height of the top bar */

.patternMiddleContainer {}
.patternLeftBar {
    top:60px; /* height of patternTopBar */
}
.patternTopBar {
    height:60px;
}

/* positioning the left bar (width:13em) */

.patternLeftBar,
.patternLeftBarContents /* needed for Explorer 5.0 */ {
    width:16%;
}
.patternMain {
    margin:0 0 0 16%;
}
.patternBottomBar {
    margin:0 0 0 17%; /* add small margin for content offset */
}

/*    -----------------------------------------------------------
    Pages that are not view
    -----------------------------------------------------------    */
    
.patternNoViewPage .patternMain {
    margin-left:3%;
    margin-right:3%;
    /* padding in style.css */
}

/* Print */

.patternPrintPage .patternMain {
    margin-left:5%;
    margin-right:5%;
}
.patternPrintPage .patternBottomBar {
    margin-left:5%;
    margin-right:0;
    padding:0;
}
/* Plain */

.patternPlainPage .patternMain {
    margin-left:0px;
    margin-right:0px;
    /* padding in style.css */
}


/*    -----------------------------------------------------------
    STYLE
    Appearance: margins, padding, fonts, borders
    -----------------------------------------------------------    */
    

/*    ---------------------------------------------------------------------------------------
    CONSTANTS
    
    Sizes
    ----------------------------------------
    S1 line-height                                                                    1.4em
    S2 somewhat smaller font size                                                    94%
    S3 small font size, twikiSmall                                                    85%
    S4 horizontal bar padding (h2, patternTop)                                        5px
    S5 form and attachment padding                                                    20px

    ---------------------------------------------------------------------------------------    */

/*    -----------------------------------------------------------
    General elements
    -----------------------------------------------------------    */
    
/* HTML elements */
html body {
    line-height:1.4em; /*S1*/
    font-family:"Lucida Grande", verdana, arial, sans-serif;
    margin:0em;
    padding:0em;
    font-size:x-small;
    voice-family:"\"}\""; 
    voice-family:inherit;
    font-size:small;
}
html>body { /* Mozilla */
    font-size:small;    
}
p {
    margin:1em 0 0 0;
}
table {
    border-collapse:separate;
}
th {
    line-height:1.15em;
}
strong, b {
    font-weight:bold;
}
hr {
    height:1px;
    border:none;
}
pre, code, tt {
    font-size:100%;
    line-height:1.4em; /*S1*/
}
/* put overflow pre in a scroll area */
pre {
    overflow-x:auto;
    overflow-y:visible;
    padding-bottom:1.5em;
    width:100%;
}
html>body pre { /* hide from IE */
    padding-bottom:0;
    /*\*/ overflow:auto !important; /* */ overflow:scroll; width:auto; /* for Mac Safari */
}
ol li, ul li {
    line-height:1.4em; /*S1*/
}
    
/* Text */
h1, h2, h3, h4, h5, h6 {
	font-family:"Lucida Grande", arial, verdana, sans-serif;
	line-height:104%;
	padding:0em;
	margin:1em 0 .1em 0;
}
h1, h2 {
	font-weight:500;
}
h1,
.patternPreviewArea h1 {
	font-size:200%;
	margin:0 0 .5em 0;
}
.patternNoViewPage h1 {
	font-size:175%;
}
.patternTopic h2,
.patternTopic h3,
.patternTopic h4,
.patternTopic h5 {
	display:block;
	/* give header a background color for easy scanning: */
	padding:.2em 5px;
	margin:1em -5px .35em -5px;
	border-width:0 0 1px 0;
	border-style:solid;
	height:auto;
	
}


/* Links */
/* somehow the twikiNewLink style have to be before the general link styles */
.twikiNewLink {
    border-width:0 0 1px 0;
    border-style:dotted;
}
.twikiNewLink a {
    text-decoration:none;
    margin-left:1px;
}
.twikiNewLink a sup {
    text-align:center;
    padding:0 2px;
    vertical-align:baseline;
    font-size:100%;
    text-decoration:none;
}
.twikiNewLink a:link sup,
.twikiNewLink a:visited sup {
    border-width:1px;
    border-style:solid;
    text-decoration:none;
}
.twikiNewLink a:hover sup {
    text-decoration:none;
}

:link:focus,
:visited:focus,
:link,
:visited,
:link:active,
:visited:active {
    text-decoration:underline;
}
:link:hover,
:visited:hover {
    text-decoration:none;
}

img {
    vertical-align:text-bottom;
}

/* Forms */
form { 
    display:inline;
    margin:0em;
    padding:0em;
}
textarea,
input,
select {
    font-size:100%;
    vertical-align:middle;
    border-width:1px;
    border-style:solid;
    padding:1px;
}
input {
    margin:.15em 0;
}
textarea {
    font-family:"Lucida Grande", verdana, arial, sans-serif;
}
label {
    vertical-align:middle;
}

/*    -----------------------------------------------------------
    Plugin elements
    -----------------------------------------------------------    */
    
/* TablePlugin */
.twikiTable {
    border-collapse: collapse;
    border-width:1px;
    border-style:solid;
}
.twikiTable td,
.twikiTable th {
    border-width:0 1px;
    border-style:solid;
}
.twikiTable th {
    padding:.4em .5em;
}
.twikiTable td {
    padding:.25em .5em;
}
.twikiTable th a:link,
.twikiTable th a:visited,
.twikiTable th a font {
    text-decoration:none;
}
.twikiTable th a:hover,
.twikiTable th a:hover font {
    text-decoration:none;
    border-width:0 0 1px 0;
    border-style:solid;
}

/* TablePlugin - sorting of table columns */
th.twikiSortedAscendingCol a:link,
th.twikiSortedAscendingCol a:link font,
th.twikiSortedAscendingCol a:visited,
th.twikiSortedAscendingCol a:visited font,
.twikiAttachments th.twikiSortedAscendingCol a:link,
.twikiAttachments th.twikiSortedAscendingCol a:link font,
.twikiAttachments th.twikiSortedAscendingCol a:visited,
.twikiAttachments th.twikiSortedAscendingCol a:visited font {
    text-decoration:none;
    border-width:1px 0 0 0;
    border-style:solid;    
}
th.twikiSortedDescendingCol a:link,
th.twikiSortedDescendingCol a:link font,
th.twikiSortedDescendingCol a:visited,
th.twikiSortedDescendingCol a:visited font,
.twikiAttachments th.twikiSortedDescendingCol a:link,
.twikiAttachments th.twikiSortedDescendingCol a:link font,
.twikiAttachments th.twikiSortedDescendingCol a:visited,
.twikiAttachments th.twikiSortedDescendingCol a:visited font {
    text-decoration:none;
    border-width:0 0 1px 0;
    border-style:solid;
}
th.twikiSortedAscendingCol a:hover,
th.twikiSortedAscendingCol a:hover font,
th.twikiSortedDescendingCol a:hover,
th.twikiSortedDescendingCol a:hover font,
.twikiAttachments th.twikiSortedAscendingCol a:hover,
.twikiAttachments th.twikiSortedAscendingCol a:hover font,
.twikiAttachments th.twikiSortedDescendingCol a:hover,
.twikiAttachments th.twikiSortedDescendingCol a:hover font{
    text-decoration:none;
    border:0;
}
th.twikiSortedAscendingCol a:hover,
th.twikiSortedAscendingCol a:hover font,
.twikiAttachments th.twikiSortedAscendingCol a:hover,
.twikiAttachments th.twikiSortedAscendingCol a:hover font {
    border-width:0 0 1px 0;
    border-style:solid;
}
th.twikiSortedDescendingCol a:hover,
th.twikiSortedDescendingCol a:hover font,
.twikiAttachments th.twikiSortedDescendingCol a:hover,
.twikiAttachments th.twikiSortedDescendingCol a:hover font {
    border-width:1px 0 0 0;
    border-style:solid;    
}

/* TipsContrib */
.tipsOfTheDayContents .tipsOfTheDayTitle {
    font-weight:bold;
}
.patternTopic .tipsOfTheDayHeader {
    display:block;
    padding:3px 5px;
}
.patternTopic .tipsOfTheDayText {
    padding:0 5px 5px 5px;
}
.patternTopic .tipsOfTheDayText a:link,
.patternTopic .tipsOfTheDayText a:visited {
    text-decoration:none;
}
/* TipsContrib - in left bar */
.patternLeftBar .tipsOfTheDay {
    margin:1em 0 .5em 0;
    border-width:0;
}
.patternLeftBar .tipsOfTheDayHeader img {
    display:none;
}
.patternLeftBar .tipsOfTheDayContents {
    padding:.25em .25em .5em .25em;
}
.patternLeftBar .tipsOfTheDayHeader {
    display:block;
    font-weight:normal;
}

/* TwistyContrib */
a:link.twistyTrigger,
a:visited.twistyTrigger {
    text-decoration:none;
}
a:link .twistyLinkLabel,
a:visited .twistyLinkLabel {
    text-decoration:underline;
}

/*    -----------------------------------------------------------
    TWiki styles
    -----------------------------------------------------------    */

.twikiAttachments,
.twikiForm {
    margin:1em 0;
}
.patternContent .twikiAttachments,
.patternContent .twikiForm {
    font-size:94%; /*S2*/
    padding:20px; /*S5*/
    border-width:1px 0 0 0;
    border-style:solid;
    margin:0 0 -1px 0;
}
.twikiAttachments p { /* fix for extra generated paragraph */
    display:none;
}
.twikiAttachments table,
.twikiForm table {
    border-collapse:collapse;
    padding:0px;
    border-spacing:0px;
    empty-cells:show;
    border-style:solid;
    border-width:1px 1px 0 1px;
}
.twikiAttachments table {
    line-height:1.4em; /*S1*/
    width:auto;
    voice-family: "\"}\""; /* hide the following for Explorer 5.x */
    voice-family:inherit;
    width:100%;
}
.twikiAttachments th,
.twikiForm th,
.twikiAttachments th,
.twikiForm th {
    padding:.2em .6em;
    height:2.5em;
    vertical-align:middle;
    border-style:solid;
    border-width:0 0 1px 1px;
}
.twikiAttachments th.twikiFirstCol,
.twikiForm th.twikiFirstCol {
    border-left:none;
    width:0px;
}
/* don't show any of those ugly sort icons */
.twikiAttachments th img,
.twikiAttachments th a:link img,
.twikiAttachments th a:visited img {
    display:none;
}
.twikiAttachments td,
.twikiForm td {
    border-style:solid;
    border-width:0 0 1px 0;
    padding:.2em .6em;
    height:1.4em; /*S1*/
    text-align:left;
    vertical-align:top;
}
.twikiForm th.twikiFirstCol,
.twikiForm td.twikiFirstCol {
    border-left:none;
}
.twikiAttachments th.twikiFirstCol,
.twikiAttachments td.twikiFirstCol {
    border-left:none;
    width:26px;
    text-align:center;
}
.twikiAttachments th a:link,
.twikiAttachments th a:visited,
.twikiForm th a:link,
.twikiForm th a:visited {
    text-decoration:none;
}
.twikiAttachments th a:hover,
.twikiForm th a:hover {
    text-decoration:none;
    border-width:0 0 1px 0;
    border-style:solid;
}
.twikiAttachments td a:link,
.twikiAttachments td a:visited,
.twikiForm td a:link,
.twikiForm td a:visited {
    font-weight: normal;
}
.twikiForm table table,
.twikiForm table table th,
.twikiForm table table td {
    border:none;
}


.twikiToc {
    margin:1em 0;
    padding:.3em 0 .6em 0;
}
.twikiToc ul {
    list-style:outside; /* list style image is set in twiki.pattern.tmpl */
    padding:0 0 0 .5em;
    margin:0em;
}
.twikiToc li {
    margin-left:1em;
}
.twikiToc .twikiTocTitle {
    margin:0em;
    padding:0em;
    font-weight:bold;
}

.twikiSmall {
    font-size:85%; /*S3*/
}
.twikiSmallish {
    font-size:94%; /*S2*/
}
.twikiNew { }
.twikiSummary {
    font-size:85%; /*S3*/
}
.twikiEmulatedLink {
    text-decoration:underline;
}
.twikiPageForm table {
    width:100%;
    border-width:1px;
    border-style:solid;
    margin:0 0 2em 0;
}
.twikiPageForm th,
.twikiPageForm td {
    border:0;
    padding:.15em;
}
.twikiPageForm td {}
.twikiPageForm th.last,
.twikiPageForm td.last {
    border-bottom:0;
}
.twikiPageForm td.first {
    padding-top:1em;
}
.twikiBroadcastMessage {
    padding:.25em;
}
.twikiButton, 
.twikiSubmit {
    font-size:100%;
    border-width:1px;
    border-style:solid;
    vertical-align:middle;
    padding:1px;
}
.twikiCheckbox,
.twikiRadioButton {
    border:none;
    vertical-align:middle;
    margin:0 .3em 0 0;
}
.twikiHelp {
    padding:1em;
    margin:.5em 0 1em 0;
    border-width:1px 0;
    border-style:solid;
}
.twikiHelp ul,
.twikiHelp li {
    margin-top:0;
    margin-bottom:0;
}
.twikiAccessKey {
    text-decoration:none;
    border-width:0 0 1px 0;
    border-style:solid;
}
a:hover .twikiAccessKey {
    text-decoration:none;
    border:none;
}

/*    -----------------------------------------------------------
    Pattern skin specific elements
    -----------------------------------------------------------    */

.patternSeparator {
    font-family:monospace;
}

.patternTopicAction {
    font-size:94%; /*S2*/
    line-height:1.5em;
    margin:0 0 3em 0;
    padding:.5em 20px; /*S5*/
    border-width:1px 0;
    border-style:solid;
}
.patternActionButtons a:link,
.patternActionButtons a:visited {
    padding:1px 1px 2px 1px;
}
.patternTopicAction .patternActionButtons a:link,
.patternTopicAction .patternActionButtons a:visited {
    text-decoration:none;
}
.patternTopicAction .patternSaveOptions {
    margin-bottom:.5em;
}
.patternTopicAction .patternSaveOptions .patternSaveOptionsContents {
    padding:.2em 0;
}
.patternMoved {
    font-size:94%; /*S2*/
    margin-bottom:1em;
}    
.patternWebIndicator {}
.patternPage {
    font-size:100%;
}
.patternMiddleContainer {}
.patternMain {
    padding:0 1.5em 1em 2em;
    border-width:1px;
    border-style:solid;
}
.patternNoViewPage .patternMain {
    padding-top:2em;
    padding-bottom:2em;
    margin-bottom:1em;
}

/* Top bar */

.patternTopBar {}
.patternTopBarContents {
    margin:0em;
    padding:5px 2em 5px 1em; /* right padding same as .patternViewPage .patternMain */ 
}
.patternTopBarContents table {
    height:50px; /* together with a padding of 2x 5px this assumes a logo of 40px height */
}
.patternTopBarContents .patternSearchBox td {
    height:50px;
    vertical-align:middle;
    font-size:94%; /*S2*/
}
.patternMetaNav {
    font-size:85%; /*S3*/
}
.patternMetaNav a:link,
.patternMetaNav a:visited {
    text-decoration:none;
}
.patternMetaNav .patternSeparator {
    margin:0 .5em;
}
.patternMetaNav input#quickSearchBox,
.patternMetaNav input#jumpBox {
    margin:0 0 0 .85em;
    padding:0;
    height:1.2em; /* 85% of default line-height 1.4 */
}
.patternMetaNav input#quickSearchButton,
.patternMetaNav input#jumpButton {
    margin:0 0 0 2px;
    border:0;
}

/* Left bar */
.patternLeftBar {
    border-width:1px 1px 1px 0;
    border-style:solid;
    overflow:hidden;
    font-size:94%; /*S2*/
}
.patternLeftBar a img {
    margin:1px 0 0 0;
}
.patternLeftBar a:link,
.patternLeftBar a:visited {
    text-decoration:none;
}
.patternLeftBar ul {
    padding:0em;
    margin:0em;
    list-style:none;
}
.patternLeftBar li {
    padding-left:0;
}
.patternLeftBar .patternLeftBarContents {
    margin:-1px 0 1em 0;
    padding:0 .5em 0 1em;
    width:89%;
}
.patternLeftBar .patternForm {
    margin:.5em 0 1em 0;
}
html>body .patternLeftBar .patternForm { /* Hide from IE */
    margin:1.25em 0 1em 0;
}
.patternLeftBar .patternFormElements {
    margin:0 0 3px 0;
    width:100%;
}
.patternLeftBar input#quickSearchBox,
.patternLeftBar input#jumpBox {
    margin:0;
    height:12px; /* with padding and border this adds up to 16px height - same as button */
    width:80%;
    border-width:1px;
    border-style:solid;
    font-size:85%; /*S3*/
}
.patternLeftBar input#quickSearchButton,
.patternLeftBar input#jumpButton {
    margin:0 0 0 4px;
    padding:0;
    border:0;
}
.patternLeftBar .patternChangeLanguage {
    margin:.2em 0 0 0;
    font-size:85%; /*S3*/
}
.patternLeftBarPersonal {
    margin:-1px 0 .7em 0;
    padding:.25em 0 .25em 1em;
    border-width:1px 0;
    border-style:solid;
}
.patternLeftBarPersonal ul {
    list-style: none;
    margin:0;
    padding:0;
}
.patternLeftBarPersonal li {
    padding-left:1em;
    background-repeat:no-repeat;
    background-position:0 .5em;
}
.patternLeftBarPersonal a:hover {
    text-decoration:none;
}

/* Bottom bar */
.patternBottomBar {
    padding-bottom:1em;
}
.patternBottomBarContents {
    padding:.5em 2.5em 1.5em .25em;
    font-size:94%; /*S2*/
}

/* table used in various places */
.patternVersatileTable table {
    width:auto;
    padding:0px;
    border-spacing:0px;
    border-collapse:collapse;
    empty-cells:show;
    border-width:1px;
    border-style:solid;
    margin:1em 0;
    font-size:94%; /*S2*/
}
.patternVersatileTable th,
.patternVersatileTable td {
    vertical-align:middle;
    border-width:1px 0 0 0;
    border-style:solid;
    padding:5px 1em 5px 1.25em; /*S4*/
}



/* Topic text */
.patternTopic {
    padding:0 0 1.5em 0;
}

.patternTop {
    font-size:94%; /*S2*/
}
.patternTop table {
    border:none;
    width:100%;
}
.patternTop td {
    vertical-align:middle;
}
.patternTop .patternHomePath,
.patternTop .patternRevInfo {
    padding:.25em .5em .25em 0;
    line-height:1.25em;
}
.patternTop .patternHomePath {
    text-align:left;
    width:auto;
}
.patternTop .patternRevInfo {
    float:right;
    text-align:right;
}
.patternTop .patternHomePath a:link,
.patternTop .patternHomePath a:visited,
.patternTop .patternRevInfo a:link,
.patternTop .patternRevInfo a:visited {
    text-decoration:none;
}

/* Button tool bar */
.patternToolBar {
    padding:.25em .5em 0 .5em;
    line-height:100%;
}
td.patternToolBar {
    vertical-align:bottom;
}
.patternToolBar a:link,
.patternToolBar a:visited {
    text-decoration:none;
}
.patternToolBarButtons {
    float:right;
}
.patternToolBarButtons .twikiSeparator {
    display:none;
}
.patternToolBar .patternButton {
    float:left;
}
.patternToolBar .patternButton s,
.patternToolBar .patternButton strike,
.patternToolBar .patternButton a:link,
.patternToolBar .patternButton a:visited {
    display:block;
    margin:0 0 -1px 4px;
    border-width:1px;
    border-style:solid;
    position:relative;
    z-index:0;
    padding:.35em .6em;
}
.patternToolBar .patternButton a:link,
.patternToolBar .patternButton a:visited {
    text-decoration:none;
}
.patternToolBar .patternButton s,
.patternToolBar .patternButton strike {
    text-decoration:none;
}
.patternToolBar .patternButton a:hover {
    text-decoration:none;
    z-index:3;
}
.patternToolBarBottom {
    position:relative;
    border-width:1px 0 0 0;
    border-style:solid;
    margin:0 0 .5em 0;
    z-index:2;
}

/* Edit page */

.twikiChangeFormButtonHolder {
    margin:1em 0;
    float:right;
}
.patternFormHolder { /* constrains the textarea */
    width:100%;
}
.twikiChangeFormButton {
    font-family:"Lucida Grande", verdana, arial, sans-serif;
    padding:0em;
    margin:0em;
    border:none;
    text-decoration:underline;
}
.patternSig {
    margin:.25em 0;
}

.patternAccessKeyInfo {
    margin-top:1em;
    padding:.25em .5em;
    border-width:1px 0;
    border-style:solid;
}
.patternAccessKeyInfo a:link,
.patternAccessKeyInfo a:visited {
    text-decoration:underline;
}
.patternAccessKeyInfo a:hover {
    text-decoration:none;
}

/* Preview page */

.patternPreviewArea {
    border-width:1px;
    border-style:solid;
    margin:0em -.5em 2em -.5em;
    padding:.5em;
}

/* Attach page */

.patternAttachPage .patternVersatileTable table {
    margin-bottom:0;
    width:auto;
    voice-family: "\"}\""; /* hide the following for Explorer 5.x */
    voice-family:inherit;
    width:100%;    
}
.patternAttachPage .patternVersatileTable th {
    text-align:right;
}
.patternPrevious {
    margin:1em 0;
}
#moveattachment {
    font-size:94%; /*S2*/
}
.patternPrevious table {
    width:auto;
}

/* Rename page */

.patternRenamePage .patternVersatileTable th {
    text-align:right;
    width:10%;
}

/* WebSearch, WebSearchAdvanced */

table#twikiSearchTable {
    background:none;
    border-bottom:0;
} 
table#twikiSearchTable th,
table#twikiSearchTable td {
    padding:.5em;
    border-width:0 0 1px 0;
    border-style:solid;
} 
table#twikiSearchTable th {
    width:15%;
    text-align:right;
}
table#twikiSearchTable td {
    width:85%;
}
table#twikiSearchTable td.first {
    padding-top:1em;
}

/*    -----------------------------------------------------------
    Search results
    styles and overridden styles used in search.pattern.tmpl
    -----------------------------------------------------------    */
    
.patternSearchResultsPage {}
.patternSearchResults {}

.patternSearchResultsHeader {
    padding:.25em 5px .15em 5px; /*S4*/
    margin:0 -5px .25em -5px; /*S4*/
    font-weight:bold;
    border-width:0 0 1px 0;
    border-style:solid;
    height:1.5em; /* or WIN/IE wont draw the backgound */
}
.patternSearchString {
    margin:1em 0 1.5em 0;
}
.patternSearchResults table {
    width:auto;
    voice-family: "\"}\""; /* hide the following for Explorer 5.x */
    voice-family:inherit;
    width:100%;
}
.patternSearchResults .twikiTopRow {
    padding-top:.2em;
}
.patternSearchResults .twikiBottomRow {
    padding-bottom:.25em;
    border-width:0 0 1px 0;
    border-style:solid;
}
.patternSearchResults .twikiAlert {
    font-weight:bold;
}
.patternSearchResults .twikiSummary .twikiAlert {
    font-weight:normal;
}
.patternSearchResults .twikiNew {
    border-width:1px;
    border-style:solid;
    font-size:85%; /*S3*/
    padding:0 1px;
    font-weight:bold;
}
.patternSearchResultsPage .twikiHelp {
    display:block;
    width:auto;
    margin:.25em 0;
}
.patternSearchResults .twikiSRAuthor {
    width:15%;
    text-align:left;
}
.patternSearchResults .twikiSRRev {
    width:30%;
    text-align:left;
}
.patternSearchResultCount {
    margin:.25em 0 1.5em 0;
    font-size:94%; /*S2*/
}
.patternViewPage .patternSearchResultsBegin { /* for changes template with noheader="on" */
    height:1px;
    border-width:0 0 1px 0;
    border-style:solid;
    padding:0 5px; /*S4*/
    margin:0 -5px; /*S4*/
}

/* Search results in book view format */

.patternBookViewList .patternSearchResultsHeader {
    margin-bottom:1em;
}
.patternBookViewList .twikiTopRow {
    padding:.2em 5px; /*S4*/
    margin:2.5em -5px .15em -5px; /*S4*/
}
.patternBookViewList .twikiBottomRow {
    font-size:100%;
    padding:1em 0;
}
.patternBookViewList .twikiBottomRow {
    width:auto;
}

/* Print */

.patternPrintPage {
    /*font-size: 12pt;*/
}
.patternPrintPage .patternMain {
    padding:1em 2em 0 2em;
    border-width:1px;
    border-style:solid;
}
.patternPrintPage .patternBottomBarContents {
    padding-left:1em;
}
.patternPrintPage .patternTopicFooter {
    margin:2em 0 2em 0;
    font-size:94%; /*S2*/
}

/* Diff */

.patternDiffPage .twikiDiffTable {
    margin:2em 0;
}
.patternDiffPage .twikiDiffTable th,
.patternDiffPage .twikiDiffTable td {
    padding:.2em;
}
tr.twikiDiffDebug td {
    border-width:1px;
    border-style:solid;
}
.patternDiffPage td.twikiDiffDebugLeft {
    border-bottom:none;
}
.twikiDiffLineNumberHeader {
    padding:.3em 0;
}


/*    -----------------------------------------------------------
    COLOR
    Appearance: text colors, background colors, border colors
    -----------------------------------------------------------    */
    
/*    ---------------------------------------------------------------------------------------
    CONSTANTS
    
    Text colors
    ----------------------------------------
    T1 text color                                                                    #000
    T2 link color                                                                    #06c
    T3 link hover text color                                                        #FBF7E8
    T4 link action button color (red) (same as BG2)                                    #D6000F
    T5 header color                                                                    #a00
    T6 code text, left bar text                                                        #7A4707
    T7 muted (dark gray) text                                                        #666
    T8 grayed out text                                                                #8E9195
    T9 alert                                                                         #f00
    T10 green 'new'                                                                    #049804
    T11 dark gray                                                                    #333
    
    Background colors
    ----------------------------------------
    BG1    white; attachment, form table background                                    #fff
    BG2 link hover background color (red)                                              #D6000F 
    BG3    light gray                                                                    #efefef
    BG4 active form field (not implemented yet)                                        #ffc
    BG5 info background very light blue    (placeholder for background image)            #E8EEF7
    BG6    patternTopicAction light yellow (same as T3)                                #FBF7E8
    BG7 header background (very light yellow)                                        #FDFAF1
    BG8 accent on sorted table column                                                #ccc
    BG9 light yellow; attachment, form background                                    #FEFBF3
    BG10 light green 'new'                                                            #ECFADC
    BG11 dark gray; diff header background (same as T8)                                #8E9195
    BG12 dark yellow, submit button                                                    #FED764
    
    Border colors
    ----------------------------------------
    BO1    light gray                                                                    #efefef
    BO2 submit button border blue ('active')                                        #88B6CF
    BO3    info light blue border                                                        #BFD8ED
    BO4 border color beige, header h2 bottom border                                    #E2DCC8
    BO5 header h3..h5 bottom border    (75% of BO4)                                    #E9E4D2
    BO6 neutral gray border                                                            #ccc
    BO7 light neutral gray                                                            #ddd
    BO9 alert border                                                                #f00

    ---------------------------------------------------------------------------------------    */
 
html body {
    background-color:#fff; /*BG1*/
    color:#000; /*T1*/
}
/* be kind to netscape 4 that doesn't understand inheritance */
body, p, li, ul, ol, dl, dt, dd, acronym, h1, h2, h3, h4, h5, h6 {
    background-color:transparent;
}
hr {
    color:#ccc; /*BO6*/
    background-color:#ccc; /*BO6*/
}
pre, code, tt {
    color:#7A4707; /*T6*/
}
h1, h2, h3, h4, h5, h6 {
    color:#a00; /*T5*/
}
h1 a:link,
h1 a:visited {
    color:#a00; /*T5*/
}
.patternTopic h2 {
    background-color:#FDFAF1;
    border-color:#E2DCC8; /*BO4*/
}
.patternTopic h3,
.patternTopic h4,
.patternTopic h5 {
    border-color:#E9E4D2; /*BO5*/
}
/* to override old Render.pm coded font color style */
.twikiNewLink font {
    color:inherit;
}
.twikiNewLink a:link sup,
.twikiNewLink a:visited sup {
    color:#666; /*T7*/
    border-color:#E2DCC8; /*BO4*/
}
.twikiNewLink a:hover sup {
    background-color:#D6000F; /*BG2*/
    color:#FBF7E8; /*C3*/
    border-color:#D6000F; /*BG2*/ /* (part of bg) */
}
.twikiNewLink {
    border-color:#666; /*T7*/
}
:link:focus,
:visited:focus,
:link,
:visited,
:link:active,
:visited:active {
    color:#06c; /*T2*/;
    background-color:transparent;
}
:link:hover,
:visited:hover {
    color:#FBF7E8; /*C3*/
    background-color:#D6000F; /*BG2*/
}
:link:hover img,
:visited:hover img {
    background:#fff; /*BG1*/
}

.patternTopic a:visited {
    color:#666; /*T7*/
}
.patternTopic a:hover {
    color:#FBF7E8; /*C3*/
}
textarea,
input,
select {
    border-color:#ccc; /*BO6*/
    background-color:#FEFBF3; /*BG9*/
}

/*    -----------------------------------------------------------
    Plugin elements
    -----------------------------------------------------------    */

/* TablePlugin */
.twikiTable,
.twikiTable td,
.twikiTable th {
    border-color:#ddd; /*BO7*/
}
.twikiTable th a:link,
.twikiTable th a:visited,
.twikiTable th a font {
    color:#06c; /*T2*/
}
.twikiTable th a:hover,
.twikiTable th a:hover font {
    background-color:transparent;
    color:#D6000F; /*T4*/
    border-color:#D6000F; /*T4*/
}

/* TablePlugin - sorting of table columns */
.patternTopic th.twikiSortedAscendingCol,
.patternTopic th.twikiSortedDescendingCol {
    background-color:#ccc; /*BG8*/
}
th.twikiSortedAscendingCol a:link,
th.twikiSortedAscendingCol a:link font,
th.twikiSortedAscendingCol a:visited,
th.twikiSortedAscendingCol a:visited font,
.twikiAttachments th.twikiSortedAscendingCol a:link,
.twikiAttachments th.twikiSortedAscendingCol a:link font,
.twikiAttachments th.twikiSortedAscendingCol a:visited,
.twikiAttachments th.twikiSortedAscendingCol a:visited font,
th.twikiSortedDescendingCol a:link,
th.twikiSortedDescendingCol a:link font,
th.twikiSortedDescendingCol a:visited,
th.twikiSortedDescendingCol a:visited font,
.twikiAttachments th.twikiSortedDescendingCol a:link,
.twikiAttachments th.twikiSortedDescendingCol a:link font,
.twikiAttachments th.twikiSortedDescendingCol a:visited,
.twikiAttachments th.twikiSortedDescendingCol a:visited font {
    border-color:#666; /*T7*/
}
th.twikiSortedAscendingCol a:hover,
th.twikiSortedAscendingCol a:hover font,
.twikiAttachments th.twikiSortedAscendingCol a:hover,
.twikiAttachments th.twikiSortedAscendingCol a:hover font,
th.twikiSortedDescendingCol a:hover,
th.twikiSortedDescendingCol a:hover font,
.twikiAttachments th.twikiSortedDescendingCol a:hover,
.twikiAttachments th.twikiSortedDescendingCol a:hover font {
    border-color:#D6000F; /*T4*/
}

/* TwistyContrib */
.twistyPlaceholder {
    color:#8E9195; /*T8*/
}
a:hover.twistyTrigger {
    color:#FBF7E8; /*T3*/
}

/* TipsContrib */
.tipsOfTheDay {
    background-color:#E8EEF7; /*BG5*/
}
.patternTopic .tipsOfTheDayHeader {
    color:#333; /*T11*/
}
/* TipsContrib - in left bar */
.patternLeftBar .tipsOfTheDay a:link,
.patternLeftBar .tipsOfTheDay a:visited {
    color:#a00; /*T5*/
}
.patternLeftBar .tipsOfTheDay a:hover {
    color:#FBF7E8; /*T3*/
}

/*    -----------------------------------------------------------
    TWiki styles
    -----------------------------------------------------------    */

.twikiGrayText a:link,
.twikiGrayText a:visited {
    color:#8E9195; /*T8*/
}
.twikiGrayText a:hover {
    color:#FBF7E8; /*C3*/
}

.twikiAttachments,
.twikiForm {
    color:#666; /*T7*/
}
.patternContent .twikiAttachments,
.patternContent .twikiForm {
    color:#333; /*T11*/
}
.patternEditPage .twikiForm {
    color:#000; /*T1*/
}
.patternContent .twikiAttachments,
.patternContent .twikiForm {
    background-color:#FEFBF3; /*BG9*/
    border-color:#E2DCC8; /*BO4*/
}
.twikiAttachments table,
.twikiForm table {
    border-color:#ccc; /*BO6*/
    background-color:#fff; /*BG1*/
}
.twikiAttachments table {
    background-color:#fff; /*BG1*/
}
.twikiAttachments th,
.twikiForm th,
.twikiAttachments th,
.twikiForm th {
    border-color:#ccc; /*BO6*/
    background-color:#fff; /*BG1*/
}
.twikiAttachments td,
.twikiForm td {
    border-color:#ccc; /*BO6*/
    background-color:#fff; /*BG1*/
}
.twikiAttachments th a:link,
.twikiAttachments th a:visited,
.twikiForm th a:link,
.twikiForm th a:visited {
    color:#06c; /*T2*/
    border-color:#06c; /*T2*/
}
.twikiAttachments th font,
.twikiForm th font {
    color:#06c; /*T2*/
}
.twikiAttachments th a:hover,
.twikiForm th a:hover {
    border-color:#06c; /*T2*/
    background-color:transparent;
}
.twikiAttachments th.twikiSortedAscendingCol,
.twikiAttachments th.twikiSortedDescendingCol {
    background-color:#efefef; /*BG3*/
}
.twikiToc .twikiTocTitle {
    color:#666; /*T7*/
}
.twikiBroadcastMessage b,
.twikiBroadcastMessage strong {
    color:#f00; /*T9*/
}
.twikiAlert,
.twikiAlert code {
    color:#f00; /*T9*/
}
.twikiGrayText {
    color:#8E9195; /*T8*/
}
.twikiEmulatedLink {
    color:#06c; /*T2*/
}
.twikiPageForm table {
    border-color:#ddd; /*BO7*/
    background:#fff; /*BG1*/
}
.twikiPageForm th {
    color:#8E9195; /*T8*/
}
.twikiPageForm td.first {
    background:#efefef; /*BG3*/
}
.twikiPageForm hr {
    border-color:#efefef; /*BO1*/
    background-color:#efefef; /*BO1*/
    color:#efefef; /*BO1*/
}
.twikiButton,
.twikiSubmit {
    border-color:#ccc; /*BO6*/
}
.twikiButton {
    background-color:#efefef; /*BG3*/
}
.twikiSubmit {
    background-color:#FED764; /*BG12*/
}
.twikiCheckbox,
.twikiRadioButton {
    background-color:transparent;
}
.twikiHelp {
    background-color:#E8EEF7; /*BG5*/
    border-color:#BFD8ED; /*BO3*/
}
.twikiAccessKey {
    color:inherit;
    border-color:#8E9195; /*T8*/
}
a:link .twikiAccessKey,
a:visited .twikiAccessKey,
a:hover .twikiAccessKey {
    color:inherit;
}

/*    -----------------------------------------------------------
    Pattern skin specific elements
    -----------------------------------------------------------    */
.patternTopicAction {
    color:#666; /*T7*/
    border-color:#E2DCC8; /*BO4*/
    background-color:#FBF7E8;
}
.patternTopicAction .twikiSeparator {
    color:#aaa;
}
.patternActionButtons a:link,
.patternActionButtons a:visited {
    color:#D6000F; /*T4*/
}
.patternActionButtons a:hover {
    color:#FBF7E8; /*C3*/
}
.patternTopicAction .twikiAccessKey {
    border-color:#C75305;
}
.patternTopicAction label {
    color:#000; /*T1*/
}
.patternHelpCol {
    color:#8E9195; /*T8*/
}
.patternWebIndicator {
    background-color:#fff;
}
.patternMain {
    background-color:#fff; /*BG1*/
    border-color:#E2DCC8; /*BO4*/
}
.patternTopBar {
    background-color:transparent;
}
.patternTopBarContents .patternSearchBox td {
    color:#8E9195; /*T8*/
}
.patternMetaNav {
    color:#8E9195; /*T8*/
}
.patternMetaNav a:link,
.patternMetaNav a:visited {
    color:#8E9195; /*T7*/
}
.patternMetaNav a:hover {
    color:#FBF7E8; /*C3*/
}
.patternMetaNav input {
    background-color:#FEFBF3; /*BG9*/
}
/* Left bar */
.patternLeftBar {
    border-color:#E2DCC8; /*BO4*/
    color:#666; /*T7*/
    background-color:transparent;
}
.patternLeftBar hr {
    color:#E2DCC8; /*BO4*/
    background-color:#E2DCC8; /*BO4*/
}
.patternLeftBar a:link,
.patternLeftBar a:visited {
    color:#7A4707; /*T6*/
}
.patternLeftBar a:hover {
    color:#FBF7E8; /*C3*/
}
.patternLeftBar b,
.patternLeftBar strong {
    color:#333; /*T11*/
}
.patternLeftBar input#quickSearchBox,
.patternLeftBar input#jumpBox {
    border-color:#E2DCC8;
}
.patternLeftBar .patternChangeLanguage {
    color:#8E9195; /*T8*/
}
.patternLeftBarPersonal {
    background-color:#E8EEF7;
    border-color:#BFD8ED; /*BO3*/
}
.patternLeftBarPersonal a:link,
.patternLeftBarPersonal a:visited {
    color:#06c; /*T2*/;
}
.patternLeftBarPersonal a:hover {
    color:#FBF7E8; /*C3*/
    background-color:#D6000F; /*BG2*/
}
.patternBottomBarContents {
    color:#8E9195;    /*T8*/
}
.patternVersatileTable table {
    border-color:#ccc;
}
.patternVersatileTable th,
.patternVersatileTable td {
    border-color:#ccc; /*BO6*/
}
.patternVersatileTable td {
    background-color:#fff; /*BG1*/
}
.patternVersatileTable th {
    background-color:#efefef;
}
.patternVersatileTable th.patternMainCol,
.patternVersatileTable td.patternMainCol {
    background-color:#ECFADC; /*BG10*/
}
.patternVersatileTable th.patternOldCol,
.patternVersatileTable td.patternOldCol {
    background-color:#fff; /*BG1*/
    color:#000;
}
.patternVersatileTable input {
    background-color:#fff; /*BG1*/
}
.patternVersatileTable input.twikiCheckbox {
    background-color:transparent;
}

.patternTop {
    color:#8E9195; /*T8*/
}
.patternTop .patternHomePath {
    color:#000; /*T1*/
}
.patternTop .patternRevInfo,
.patternTop .patternRevInfo a:link,
.patternTop .patternRevInfo a:visited {
    color:#8E9195; /*T8*/
}
.patternTop .patternRevInfo a:hover {
    color:#FBF7E8; /*C3*/
}
.patternToolBar .patternButton s,
.patternToolBar .patternButton strike,
.patternToolBar .patternButton a:link,
.patternToolBar .patternButton a:visited {
    border-color:#E2DCC8; /*BO4*/
    background-color:#fff; /*BG1*/
}
.patternToolBar .patternButton a:link,
.patternToolBar .patternButton a:visited {
    color:#666; /*T7*/
}
.patternToolBar .patternButton s,
.patternToolBar .patternButton strike {
    color:#8E9195; /*T8*/
    border-color:#e0e0e0;
    background-color:#fff; /*BG1*/
}
.patternToolBar .patternButton a:hover {
    background-color:#D6000F; /*BG2*/
    color:#FBF7E8; /*C3*/
    border-color:#D6000F; /*T4*/
}
.patternToolBarBottom {
    border-color:#E2DCC8; /*BO4*/
}
.patternToolBar a:link .twikiAccessKey,
.patternToolBar a:visited .twikiAccessKey {
    color:inherit;
    border-color:#666; /*T7*/
}
.patternToolBar a:hover .twikiAccessKey {
    background-color:transparent;
    color:inherit;
}

/* Edit page */

.patternEditPage textarea#topic {
    background-color:#fff; /*BG1*/
}
.twikiChangeFormButton {
    color:#06c; /*T2*/
    background-color:transparent;
}
.patternSig input {
    color:#8E9195; /*T8*/
    background-color:#fff; /*BG1*/
}
.patternAccessKeyInfo {
    color:#666; /*T7*/
    background-color:#E8EEF7; /*BG5*/
    border-color:#BFD8ED; /*BO3*/
}
.patternAccessKeyInfo a:link,
.patternAccessKeyInfo a:visited {
    color:#06c; /*T2*/
}
.patternAccessKeyInfo a:hover {
    color:#FBF7E8; /*T3*/
}

/* Preview page */

.patternPreviewArea {
    border-color:#f00; /*BO9*/
    background-color:#fff; /*BG1*/
}

/* WebSearch, WebSearchAdvanced */

table#twikiSearchTable th,
table#twikiSearchTable td {
    background-color:#fff; /*BG1*/
    border-color:#ddd; /*BO7*/
} 
table#twikiSearchTable th {
    color:#8E9195; /*T8*/
}
table#twikiSearchTable td.first {
    background-color:#efefef; /*BG3*/
}

/*    -----------------------------------------------------------
    Search results
    styles and overridden styles used in search.pattern.tmpl
    -----------------------------------------------------------    */

.patternSearchResultsHeader {
    background-color:#FEFBF3; /*BG9*/
    border-color:#ccc; /*BO6*/
}
.patternSearchResults .twikiBottomRow {
    border-color:#ddd; /*BO7*/
}
.patternSearchResults .twikiAlert {
    color:#f00; /*T9*/
}
.patternSearchResults .twikiSummary .twikiAlert {
    color:#900; /*C5*/
}
.patternSearchResults .twikiNew {
    background-color:#ECFADC; /*BG10*/
    border-color:#049804; /*T10*/
    color:#049804; /*T10*/
}
.patternViewPage .patternSearchResultsBegin {
    border-color:#ddd; /*BO7*/
}

/* Search results in book view format */

.patternBookViewList .twikiTopRow {
    background-color:transparent; /* set to BGCOLOR in template */
    color:#666; /*T7*/
}
.patternBookViewList .twikiTopRow a:link, 
.patternBookViewList .twikiTopRow a:visited {
    color:#FBF7E8; /*C3*/
}
.patternBookViewList .twikiTopRow a:hover {
    color:#06c; /*T2*/;
}
.patternBookViewList .twikiBottomRow {
    border-color:#ddd; /*BO7*/
}
.patternBookViewList .patternSearchResultCount {
    color:#8E9195; /*T8*/
}

/* Print */

.patternPrintPage .patternMain {
    border-color:#fff #ddd #ddd #ddd; /*BO7*/
}
.patternPrintPage .patternContent .twikiAttachments,
.patternPrintPage .patternContent .twikiForm {
    background:#fff; /*BG1*/
}

/* Diff */

tr.twikiDiffDebug td {
    border-color:#ccc; /*BO6*/
}
tr.twikiDiffDebug .twikiDiffChangedText,
tr.twikiDiffDebug .twikiDiffChangedText {
    background:#99ff99;
}
/* Deleted */
tr.twikiDiffDebug .twikiDiffDeletedMarker,
tr.twikiDiffDebug .twikiDiffDeletedText {
    background-color:#f99;
}
/* Added */
tr.twikiDiffDebug .twikiDiffAddedMarker,
tr.twikiDiffDebug .twikiDiffAddedText {
    background-color:#ccf;
}
/* Unchanged */
tr.twikiDiffDebug .twikiDiffUnchangedText {
    color:#8E9195; /*T8*/
}
/* Headers */
.twikiDiffChangedHeader,
.twikiDiffDeletedHeader,
.twikiDiffAddedHeader {
    background-color:#8E9195; /*BG11*/
}

/* Unchanged */
.twikiDiffUnchangedTextContents { }
.twikiDiffLineNumberHeader {
    background-color:#ddd;
}






/* CONFIGURE SPECIFIC */

ul {
    margin-top:0;
    margin-bottom:0;
}
.patternMain {
    margin:0 3em;
    border-top:0;
}
.logo {
    margin:1em 0 1.5em 0;
}
.formElem {
    background-color:#F3EDE7;
    margin:0.5em 0;
    padding:0.5em 1em;
}
.blockLinkAttribute {
    margin-left:0.35em;
}
.blockLinkAttribute a:link,
.blockLinkAttribute a:visited {
	text-decoration:none;
}
a.blockLink {
    display:block;
    padding:0.25em 1em;
    border-bottom:1px solid #aaa;
    text-decoration:none;
}
a:link.blockLink,
a:visited.blockLink {
    text-decoration:none; 
}
a:link:hover.blockLink {
    text-decoration:none;   
}
a:link.blockLinkOff,
a:visited.blockLinkOff {
    background-color:#F3EDE7;
    color:#333;
    font-weight:normal;
}
a:link.blockLinkOn,
a:visited.blockLinkOn {
    background-color:#b4d5ff;
    color:#333;
    font-weight:bold;
}
a.blockLink:hover {
    background-color:#1559B3;
    color:white;
}
div.explanation {
    background-color:#E8EEF7;
    padding:0.5em 1em;
    margin:0.5em 0;
}
div.specialRemark {
    background-color:#fff;
    border:1px solid #ccc;
    margin:0.5em;
    padding:0.5em 1em;
}
div.options {
    margin:1em 0;
}
div.options div.optionHeader {
    padding:0.25em 1em;
    background-color:#666;
    color:white;
    font-weight:bold;
}
div.options div.optionHeader a {
    color:#bbb;
    text-decoration:underline;
}
div.options div.optionHeader a:link:hover,
div.options div.optionHeader a:visited:hover {
    color:#b4d5ff; /* King's blue */
    background-color:#666;
    text-decoration:underline;
}
div.options .twikiSmall {
    margin-left:0.5em;
    color:#bbb;
}
div.foldableBlock {
    border-bottom:1px solid #ccc;
    border-left:1px solid #ddd;
    border-right:1px solid #ddd;
    height:auto;
    width:auto;
    overflow:auto;
    padding:0.25em 0 0.5em 0;
}
.foldableBlockOpen {
    display:block;
}
.foldableBlockClosed {
    display:block;
}
div.foldableBlock table {
    margin-bottom:1em;
}
div.foldableBlock td {
    padding:0.15em 1em;
    border-top:1px solid #ddd;
}
.info {
    color:#666; /*T7*/ /* gray */
    background-color:#E8EEF7; /*BG5*/ /* light blue */
    margin-bottom:0.25em;
    padding:0.25em 0;
}
.warn {
    color:#f60; /* orange */
    background-color:#FFE8D9; /* light orange */
    border-bottom:1px solid #f60;
}
a.info,
a.warn,
a.error {
	text-decoration:none;
}
.error {
    color:#f00; /*T9*/ /*red*/
    background-color:#FFD9D9; /* pink */
    border-bottom:1px solid #f00;
}
.mandatory,
.mandatory input {
    color:green;
    background-color:#ECFADC;
    font-weight: bold;
}
.mandatory {
    border-bottom:1px solid green;
}
.mandatory input {
    font-weight:normal;
}
.docdata {
    padding-top: 1ex;
    vertical-align: top;
}
.keydata {
    font-weight: bold;
    background-color:#FOFOFO;
    vertical-align: top;
}
.subHead {
    font-weight: bold;
    font-style: italic;
}
.firstCol {
    width: 30%;
    font-weight: bold;
    vertical-align: top;
}
.secondCol {
}
.hiddenRow {
    display:none;
}
HERE

my $js2 = <<'HERE';
//<!--

document.write("<style type='text/css'>");
document.write(".foldableBlockClosed {display:none;}");
document.write("<\/style>");
//-->
HERE

my $hdr = CGI::start_html(
    -title => 'TWiki Configuration',
    -head => [
        CGI::meta({ 'http-equiv'=>'Pragma', content=>'no-cache' }),
        CGI::meta({ 'http-equiv'=>'Cache-Control', content=>'no-cache' }),
        CGI::meta({ 'http-equiv'=>'Expires', content=>0 }),
        CGI::meta({ name=>'robots', content=>'noindex' }),
        CGI::Link( { -rel=>'icon', -href=>$ENV{SCRIPT_NAME}.'?action=image;image=favicon.ico;type=image/x-icon', -type=>'image/x-icon' } ),
        CGI::Link( { -rel=>'shortcut icon', -href=>$ENV{SCRIPT_NAME}.'?action=image;image=logos/favicon.ico;type=image/x-icon', -type=>'image/x-icon' } ),
        CGI::script( { language => 'JavaScript',
                       type => 'text/javascript' }, $js1 ),
        CGI::style( { -type=>'text/css' }, $css),
        CGI::script( { language => 'JavaScript',
                       type => 'text/javascript' }, $js2 ),
       ]);

# XML confuses IE, so strip it out. This is fixed in CGI.pm 3.06.
$hdr =~ s/^<\?xml.*?>//s;
print CGI::header('text/html'), $hdr;

my $body = "";
$body .= CGI::img({src=>$ENV{SCRIPT_NAME}.'?action=image;image=T-logo-140x40-t.gif;type=image/gif', class=>'logo', alt=>'TWiki'});
$body .= CGI::h1( 'Configuration');

my $update_disabled = 0;
my $path_to_localsite_cfg = _findFileOnPath('LocalSite.cfg');
unless( $path_to_localsite_cfg ) {
    $path_to_localsite_cfg = _findFileOnPath('TWiki.cfg') || '';
    $path_to_localsite_cfg =~ s/TWiki\.cfg/LocalSite.cfg/;
}
my $errs;
if( !$path_to_localsite_cfg ||
    ( $errs = _checkCanCreateFile( $path_to_localsite_cfg ))) {
    $errs ||= 'Cannot locate LocalSite.cfg. Is your setting for $twikiLibPath correct in bin/LocalLib.cfg?';
    $body .= CGI::p(WARN('Save is disabled; '.$errs));
    $update_disabled = "Cannot create $path_to_localsite_cfg - are permissions correct?";
}

if( $action eq 'update' ) {
    if( $update_disabled ) {
        die ERROR( "Update is disabled $update_disabled" );
    }
    $body .= handleUpdate( $path_to_localsite_cfg );
} else {
    $body .=  "<p><strong>Use this page to set the configuration options for TWiki. Fill in the settings, and then press 'Next'.</strong></p>";
    $body .=  "<div class=\"explanation\"><div class=\"specialRemark\">";
    $body .= CGI::img({src=>$ENV{SCRIPT_NAME}.'?action=image;image=info.gif;type=image/gif', alt=>''}) . '&nbsp;';
    $TWiki::cfg{ScriptUrlPath} ||= '';
    $TWiki::cfg{ScriptSuffix} ||= '';
    $TWiki::cfg{SystemWebName} ||= '';
    $body .= <<HERE;
<b>If you are installing TWiki for the first time</b><br />If you just want to get up and running, the only section you need to worry about below is
<a rel="nofollow" href="#" onclick="foldBlock('GeneralPathSettings'); return false;">General path settings</a>. You can always come
back and configure other settings later.</div>
<ul>
    <li><b>If your TWiki site is already working</b>, continue to <a rel="nofollow" href="$TWiki::cfg{ScriptUrlPath}/view$TWiki::cfg{ScriptSuffix}/$TWiki::cfg{SystemWebName}/TWikiReferenceManual">browse to the TWiki Reference Manual</a>.<ul>
<li>You will now need to consider how you are going to manage authentication and access control. See the reference manual sections on <a rel="nofollow" href="$TWiki::cfg{ScriptUrlPath}/view$TWiki::cfg{ScriptSuffix}/$TWiki::cfg{SystemWebName}/TWikiUserAuthentication">authentication</a> and <a rel="nofollow" href="$TWiki::cfg{ScriptUrlPath}/view$TWiki::cfg{ScriptSuffix}/$TWiki::cfg{SystemWebName}/TWikiAccessControl">access control</a>, and the <a rel="nofollow" href="#" onclick="foldBlock(\'SecuritySetup\'); return false;">Security Setup</a> section below.</li></ul></li>
<li><b>If you are on an odd platform</b> there are a lot of topics on TWiki.org describing <a href="http://twiki.org/cgi-bin/view/Codev/CategoryCookbook">how to
configure TWiki for different platforms</a>.</li>
<li><b>If you get stuck</b> there is a lot of support available on <a href="http://twiki.org/cgi-bin/view/Codev/TWikiIRC">TWikiIRC</a> (irc.freenode.net, channel #twiki) and at <a href="http://twiki.org/cgi-bin/view/Support/WebHome">TWiki:Support</a>.</li>
</ul>
</div>
<div class="remark">Explanation of color codes:
<ul style="margin-top:0;">
<li>Settings marked <span class='mandatory'>like this</span> are required (they must
have a value).</li>
<li>Any <span class='error'>errors</span> in your configuration will be highlighted.</li>
<li><span class='warn'>Warnings</span> are non-fatal, but are often a good indicator that something that is wrong.</li>
</ul></div>
HERE

    $body .= performSanityChecks( $brokenTWikiCfgError, $brokenLocalSiteError );

    my $options = '';
    unless( $update_disabled ) {
        $body .= CGI::start_form({ action=>$ENV{SCRIPT_NAME},method=>"post" });
        # use time to make sure we never allow cacheing
        $options .= CGI::hidden( 'action', 'update' );
        $options .= CGI::hidden( 'time', time() );
    }
    $options .= CGI::div({ class => 'optionHeader'}, 
        CGI::span({ class => 'twikiLeft' }, 'Settings' . 
            CGI::span({ class => 'twikiSmall' },
                      'Click the buttons below to open each section')).
            CGI::span({ class => 'twikiSmall twikiRight' },
                CGI::a({ href => '#', rel => 'nofollow',
                         onclick => 'toggleAllOptions(true); return false;'}, 'Open all options')).
            CGI::br());

    $options .= presentReadOnlyInfo();

    $options .= presentEditableInfo();

    $body .= CGI::div({class=>'options', id=>'options'}, $options);
    my $totwarningsMess = ($totwarnings > 1) ? ' warnings' : ' warning';
    $body .= CGI::div('Total: '.CGI::span(
        {class=>'warn'}, $totwarnings . $totwarningsMess)) if $totwarnings;
    my $toterrorsMess = ($toterrors > 1) ? ' errors' : ' error';
    $body .= CGI::div('Total: ' . CGI::span(
        {class=>'error'}, $toterrors . $toterrorsMess)) if $toterrors;

    if( $update_disabled) {
        $body .= CGI::em("Update is disabled - $update_disabled");
    } else {
        $body .= CGI::p(CGI::submit(-class=>'twikiSubmit', -value=>'Next', -accesskey=>'N'));
        $body .= CGI::end_form();
    }

}
print CGI::div({class => 'patternMain'}, $body);
print CGI::end_html();

1;
