#!/usr/bin/perl
#
# 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, PASSWORD
# 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;
use warnings;

$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 && $script !~ /\.cfg$/ && !-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 password types
sub _PROMPT_FOR_PASSWORD {
    my( $id, $opts, $value, $keys ) = @_;
    my $size = "55%";
    if( $opts =~ /\s(\d+)\s/ ) {
        $size = $1;
        # These numbers are somewhat arbitrary..
        if($size>25) { $size="55%"; }
    }

    # 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::password_field( -name => $id, -size=>$size, -default=>'--------' );
}

# generate an input field for string types
sub _PROMPT_FOR_STRING {
    my( $id, $opts, $value, $keys ) = @_;
    my $size = "55%";
    if( $opts =~ /\s(\d+)\s/ ) {
        $size = $1;
        # These numbers are somewhat arbitrary..
        if($size>25) { $size="55%"; }
    }

    # 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=>"55%", -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=>"55%", -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=>"55%", -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 ) = @_;
    $value =~ s/[[\x01-\x09\x0b\x0c\x0e-\x1f"%&'*<=>@[_\|]/'&#'.ord($&).';'/ge;
    return '<input name="'.$id.'" type="text" size="55%" value="'.$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=>"55%", -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);
}

# generate an input field for SELECTCLASS types
# Takes a comma-separated list of options
# Each option must be either 'none' or a wildcard expression that matches classes e.g.
# TWiki::Plugins::*Plugin
# * is the only wildcard supported
# Finds all classes that match in @INC
sub _PROMPT_FOR_SELECTCLASS {
    my( $id, $opts, $value, $keys ) = @_;
    $opts =~ s/^\s*(.*)\s*$/$1/;
    my $sopts = '';
    if ( defined($value) ) {
    	$sopts .= '<option selected="selected">'.$value.'</option>';
    }
    foreach my $opt (split( /\s*,\s*/, $opts)) {
        if ($opt eq 'none') {
            $sopts .= '<option>none</option>';
        } else {
            foreach my $class (_findClasses($opt)) {
                $sopts .= '<option>'.$class.'</option>' unless $class eq $value;
            }
        }
    }
    return CGI::Select({ name => $id, size=>1 }, $sopts);
}

# $pattern is a wildcard expression that matches classes e.g.
# TWiki::Plugins::*Plugin
# * is the only wildcard supported
# Finds all classes that match in @INC
sub _findClasses {
    my $pattern = shift;

    $pattern =~ s/^\s+//;
    $pattern =~ s/\s+$//;
    $pattern =~ s/\*/.*/g;
    my @path = split(/::/, $pattern);

    my $places = \@INC;

    while (scalar(@path) > 1 && @$places) {
        my $pathel = shift(@path);
        eval "\$pathel = qr/^$pathel\$/";
        my @newplaces;

        foreach my $place (@$places) {
            if( opendir( DIR, $place ) ) {
                foreach my $subplace ( readdir DIR ) {
                    next unless $subplace =~ $pathel;
                    push(@newplaces, $place.'/'.$subplace);
                }
            }
        }
        $places = \@newplaces;
    }

    my @list;
    my $leaf = shift(@path);
    eval "\$leaf = qr/$leaf\.pm\$/";
    my %known;
    foreach my $place (@$places) {
        if (opendir( DIR, $place )) {
            foreach my $file ( readdir DIR ) {
                next unless $file =~ $leaf;
                $file =~ /^(.*)\.pm$/;
                my $module = "$place/$1";
                $module =~ s./.::.g;
                $module =~ /($pattern)$/;
                push(@list, $1) unless $known{$1};
                $known{$1} = 1;
            }
        }
    }

    return @list;
}

########################################################################
###################### 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 'C', 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;
    my @classes = _findClasses('TWiki::Plugins::*Plugin');
    foreach my $module ( @classes ) {
        $module =~ s/^.*::([^:]*)/$1/;
        $TWiki::cfg{Plugins}{$module}{Enabled} ||= 0;
        # only add the first instance of any plugin, as only
        # the first can get loaded from @INC.
        unless( $modules{$module} ) {
            $modules{$module} = 1;
        }
    }
    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 {
    # Suppress "Subroutine TWiki::O_CREAT redefined" warnings - see Bugs:Item2433
    no warnings qw(redefine);

    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 => ''},
                            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
        my $password = "";
        my $passwordtitle = CGI::h3('Enter the configuration password');
        my $passwordinput = "";
        if ($TWiki::cfg{Password} ne '') {
        	$passwordinput .= CGI::h3(CGI::strong("Your Password:"));
            $passwordinput .= CGI::p(CGI::password_field( 'cfgAccess', '', 20, 80 ) . '&nbsp;' . CGI::submit(-class=>'twikiSubmit', -value=>'Save changes'));
        } else {
			$passwordinput .= CGI::hidden( 'cfgAccess', '' );
        }
        my $passwordforgot = "";
        if ($TWiki::cfg{Password} ne '') {
            $passwordforgot .= CGI::p( CGI::strong("Forgot your password?")) . CGI::p('To reset the password, log in to the server and delete the <code>$TWiki::cfg{Password} = \'...\';</code> line in <code>lib/LocalSite.cfg</code>');
        }
        my $passwordforgothelp = CGI::img({width=>'16', height=>'16', src=>$ENV{SCRIPT_NAME}.'?action=image;image=warning.gif;type=image/gif', alt=>''}) . '&nbsp;';
        $passwordforgothelp .= CGI::span({ class=>'twikiAlert' }, CGI::strong("Notes on Security"));
        
        $passwordforgothelp .= "<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>";
        $passwordforgot .= CGI::div({ class => 'explanation'}, $passwordforgothelp);

        $password .= CGI::div({ class=>'twikiFormStep' }, $passwordtitle) unless $passwordtitle eq '';
        $password .= CGI::div({ class=>'twikiFormStep' }, $passwordinput) unless $passwordinput eq '';
        $password .= CGI::div({ class=>'twikiFormStep' }, $passwordforgot) unless $passwordforgot eq '';        
        
        $output .= CGI::div({ id =>'twikiPassword'}, CGI::div({class=>'twikiFormSteps'}, $password)) unless $changed == 0;
        
        
        my $changepassword = "";
        my $changepasswordtitle = "";
        if ($TWiki::cfg{Password} ne '') {
        	$changepasswordtitle .= CGI::h3( "You may change your password here:" );
		}
		my $changepasswordnew = "";
		$changepasswordnew .= CGI::strong("New Password:");
		$changepasswordnew .= CGI::p( CGI::password_field( 'newCfgP', '', 20, 80 ) );
		my $changepasswordconfirm = "";
		$changepasswordconfirm .= CGI::strong("Confirm Password:");
		$changepasswordconfirm .= CGI::p( CGI::password_field( 'confCfgP', '', 20, 80 ) );
		my $changepasswordsubmit = CGI::p( CGI::submit(-class=>'twikiSubmit', -value=>'Set Password and Save changes') );
                
        $changepassword .= CGI::div({ class=>'twikiFormStep' }, $changepasswordtitle) unless $changepasswordtitle eq '';        
        $changepassword .= CGI::div({ class=>'twikiFormStep' }, $changepasswordnew) unless $changepasswordnew eq '';
        $changepassword .= CGI::div({ class=>'twikiFormStep' }, $changepasswordconfirm) unless $changepasswordconfirm eq '';
        $changepassword .= CGI::div({ class=>'twikiFormStep' }, $changepasswordsubmit) unless $changepasswordsubmit eq '';

        $output .= CGI::div({ id =>'twikiPasswordChange'}, CGI::div({class=>'twikiFormSteps'}, $changepassword));

        $output .= CGI::end_form();
        return $output;
    }

    unless( crypt( $pass, $TWiki::cfg{Password}) eq
            $TWiki::cfg{Password} || $TWiki::cfg{Password} eq '') {
        $output .= CGI::span( {class => 'error' }, "Incorrect password" );
        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');
    my $languageChanged=0;
    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( $type eq 'PASSWORD' && ($val eq '--------'));
            next if( $val eq $def );
            $output .= CGI::h3($var).
              CGI::strong('old ').
              CGI::code($def||' ').
              CGI::br().
              CGI::strong('new ').
              CGI::code($val||' ');
            $updates{$basevar} = _perlifyType($val, $type);
            #SMELL: Not elegant, but works
            if ($basevar=~/\{Languages\}/) {
                $languageChanged=1;
            }
            $changed++;
        }
    }
    $output .= CGI::p();
    setConfig($path, \%updates);
    if ($languageChanged) {
        if ( -f "$TWiki::cfg{LocalesDir}/languages.cache" ) {
            unlink "$TWiki::cfg{LocalesDir}/languages.cache";
        }
    }
    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( $type eq 'PASSWORD' && ($val eq '--------'));
            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;
} elsif ( -r '../conf/setlib.cfg' ) {
    require '../conf/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';


/* 
Basic layout derived from http://www.positioniseverything.net/articles/pie-maker/pagemaker_form.php.
I've changed many so things that I won't put a full copyright notice. However all hacks (and comments!) are far beyond my knowledge and this deserves full credits:

Original copyright notice:
Parts of these notes are
(c) Big John @ www.positioniseverything.net and (c) Paul O'Brien @ www.pmob.co.uk, all of whom contributed significantly to the design of
the css and html code.

Reworked for TWiki: (c) Arthur Clemens @ visiblearea.com
*/

html, body {
	margin:0; /*** Do NOT set anything other than a left margin for the page
as this will break the design ***/
	padding:0;
	border:0;
/* \*/
	height:100%;
/* Last height declaration hidden from Mac IE 5.x */
}
body {
	background:#fff;
	min-width:100%; /*** This is needed for moz. Otherwise, the header and patternBottomBar will
slide off the left side of the page if the screen width is narrower than the design.
Not seen by IE. Left Col + Right Col + Center Col + Both Inner Borders + Both Outer Borders ***/
	text-align:center; /*** IE/Win (not IE/MAC) alignment of page ***/
}
.clear {
	clear:both;
	/*** these next attributes are designed to keep the div
	height to 0 pixels high, critical for Safari and Netscape 7 ***/
	height:0px;
	overflow:hidden;
	line-height:1%;
	font-size:0px;
}

#patternWrapper {
	height:100%; /*** moz uses this to make full height design. As this #patternWrapper is inside the #patternPage which is 100% height, moz will not inherit heights further into the design inside this container, which you should be able to do with use of the min-height style. Instead, Mozilla ignores the height:100% or min-height:100% from this point inwards to the center of the design - a nasty bug.
If you change this to height:100% moz won't expand the design if content grows.
Aaaghhh. I pulled my hair out over this for days. ***/
/* \*/
	height:100%;
/* Last height declaration hidden from Mac IE 5.x */
/*** Fixes height for non moz browsers, to full height ***/
}
#patternWrapp\65	r{ /*** for Opera and Moz (and some others will see it, but NOT Safari) ***/
	height:auto; /*** For moz to stop it fixing height to 100% ***/
}
/* \*/
* html #patternWrapper{
	height:100%;
}

#patternPage {
	margin-left:auto; /*** Mozilla/Opera/Mac IE 5.x alignment of page ***/
	margin-right:auto; /*** Mozilla/Opera/Mac IE 5.x alignment of page ***/
	text-align:left; /*** IE Win re-alignment of page if page is centered ***/
	position:relative;
	width:100%; /*** Needed for Moz/Opera to keep page from sliding to left side of
page when it calculates auto margins above. Can't use min-width. Note that putting
width in #patternPage shows it to IE and causes problems, so IE needs a hack
to remove this width. Left Col + Right Col + Center Col + Both Inner Border + Both Outer Borders ***/
/* \*/
	height:100%;
/* Last height declaration hidden from Mac IE 5.x */
/*** Needed for Moz to give full height design if page content is
too small to fill the page ***/
}
/* Last style with height declaration hidden from Mac IE 5.x */
/*** Fixes height for IE, back to full height,
from esc tab hack moz min-height solution ***/
#patternOuter {
	z-index:1; /*** Critical value for Moz/Opera Background Column colors fudge to work ***/
	position:relative; /*** IE needs this or the contents won't show outside the parent container. ***/

	height:100%;
/* Last height declaration hidden from Mac IE 5.x */
/*** Needed for full height inner borders in Win IE ***/
}

#patternFloatWrap {
	width:100%;
	float:left;
	display:inline;
}

#patternLeftBar {
	/* Left bar width is defined in viewleftbar.pattern.tmpl */
	float:left;
	display:inline;
	position:relative; /* IE needs this or the contents won't show
outside the parent container. */
	overflow:hidden;
}
#patternLeftBarContents {
	left:-1px;
	position:relative;
	/* for margins and paddings use style.css */
}
#patternMain {
	width:100%;
	float:right;
	display:inline;
}
#patternTopBar {
	/* Top bar height is defined in viewtopbar.pattern.tmpl */
	z-index:1; /*** Critical value for Moz/Opera Background Column colors fudge to work ***/
	position:absolute;
	top:0px;
	width:100%;
}
#patternTopBarContents {
	height:1%; /* or Win IE won't display a background */
	/* for margins/paddings use style.css */
}
#patternBottomBar {
	z-index:1; /* Critical value for Moz/Opera Background Column colors fudge to work */
	clear:both;
	width:100%;
}

/* Pages that are not view */

.patternNoViewPage #patternOuter {
	/* no left bar, margin at both sides */
	margin-left:4%;
	margin-right:4%;
}

/* edit.pattern.tmpl */

.patternEditPage #patternOuter,
.patternPreviewPage #patternOuter {
	margin-left:0;
	margin-right:0;
}

.twikiLeft {
	float:left;
	position:relative;
}
.twikiRight {
	position:relative;
	float:right;
	display:inline;
	margin:0;
}
.twikiClear {
	/* to clean up floats */
	margin:0;
	padding:0;
	height:0;
	line-height:0px;
	clear:both;
	display:block;
}
.twikiHidden {
	display:none;
}
.twikiLast,
.patternTopic .twikiLast {
	border-bottom:0px;
}

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

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

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

/* GENERAL HTML ELEMENTS */

html body {
	font-size:104%; /* to change the site's font size, change #patternPage below */
	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;
}

/* put overflow pre in a scroll area */
pre {
    width:100%;
    margin:1em 0; /* Win IE tries to make this bigger otherwise */
}
html>body pre { /* hide from IE */
	/*\*/ overflow:auto !important; /* */ overflow:scroll; width:auto; /* for Mac Safari */
}
/* IE behavior for pre is defined in twiki.pattern.tmpl in conditional comment */
ol li, ul li {
	line-height:1.4em; /*S1*/
}
	
/* Text */
h1, h2, h3, h4, h5, h6 {
	line-height:104%;
	padding:0em;
	margin:1em 0 .1em 0;
	font-weight:normal;
}
h1 {
	margin:0 0 .5em 0;
}
h1 { font-size:210%; }
h2 { font-size:160%; }
h3 { font-size:135%; }
h4 { font-size:122%; }
h5 { font-size:110%; }
h6 { font-size:95%; }
h2, h3, h4, h5, h6 {
	display:block;
	/* give header a background color for easy scanning:*/
	padding:.1em 5px;
	margin:1em -5px .35em -5px;
	border-width:0 0 1px 0;
	border-style:solid;
	height:auto;	
}
h1.patternTemplateTitle {
	font-size:175%;
	text-align:center;
}
h2.patternTemplateTitle {
	text-align:center;
}
/* Links */
/* somehow the twikiNewLink style have to be before the general link styles */
.twikiNewLink {
	border-width:0 0 1px 0;
	border-style:solid;
}
.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;
	border:0;
}

/* Form elements */
form { 
	display:inline;
	margin:0em;
	padding:0em;
}
textarea,
input,
select {
	vertical-align:middle;
	border-width:1px;
	border-style:solid;
}
textarea {
	padding:1px;
}
input,
select option {
	padding:1px;
}
.twikiSubmit,
.twikiButton,
.twikiCheckbox {
	border-width:1px;
	border-style:solid;
	padding:.15em .25em;
	font-size:94%;
	font-weight:bold;
	vertical-align:middle;
}
.twikiCheckbox,
.twikiRadioButton {
	margin:0 .3em 0 0;
	border:0;
}
.twikiInputField {
	border-width:1px;
	border-style:solid;
	padding:.15em .25em;
	font-size:94%; /*S2*/
}
.patternFormButton {
	border:0;
	margin:0 0 0 2px;
}
textarea {
	font-size:100%;
}

/* LAYOUT ELEMENTS */
/* for specific layout sub-elements see further down */

#patternPage {
	font-family:arial, "Lucida Grande", verdana, sans-serif;
	line-height:1.4em; /*S1*/
	/* change font size here */
	font-size:105%;
}
#patternTopBar {
	border-width:0 0 1px 0;
	border-style:solid;
	overflow:hidden;
}
#patternTopBarContents {
	padding:0 1.5em 0 1em;
}
#patternBottomBar {
	border-width:1px 0 0 0;
	border-style:solid;
}
#patternBottomBarContents {
	padding:1em;
	font-size:86%; line-height:110%; /*S3*/
	text-align:center;
}
#patternMainContents {
	padding:0 1.5em 3em 3em;
}
#patternLeftBarContents {
	margin:0 1em 1em 1em;
}

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

/* EditTablePlugin */
.editTable .twikiTable {
	margin:0 0 2px 0;
}
.editTableInput,
.editTableTextarea {
	font-family:monospace;
}
.editTableEditImageButton {
	border:none;
}

/* TablePlugin */
.twikiTable {
}
.twikiTable td,
.twikiTable th {
}
.twikiTable th {
    padding:4px;
}
.twikiTable td {
    padding:2px 4px;
}
.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 {
	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 {
	border-width:0 0 1px 0;
	border-style:solid;
}
th.twikiSortedAscendingCol a:hover,
th.twikiSortedAscendingCol a:hover font {
	border-width:0 0 1px 0;
	border-style:solid;
	text-decoration:none;
}
th.twikiSortedDescendingCol a:hover,
th.twikiSortedDescendingCol a:hover font {
	border-width:1px 0 0 0;
	border-style:solid;
	text-decoration:none;
}

.twikiEditForm {
	margin:0 0 .5em 0;
}
.twikiEditForm .twikiFormTable {
	text-align:center;
}

/* 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 .tipsOfTheDayHeader img {
	/* hide lamp icon */
	display:none;
}
#patternLeftBar .tipsOfTheDayContents {
	padding:.25em .25em .5em .25em;
	height:1%; /* or Win IE won't display a background */
	overflow:hidden;
}
#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
	-----------------------------------------------------------	*/

#twikiLogin {
	width:40em;
	margin:0 auto;
	text-align:center;
}
#twikiLogin .twikiFormSteps {
	border-width:5px;
}
.twikiAttachments,
.twikiForm {
	margin:1em 0;
	padding:1px; /* fixes disappearing borders because of overflow:auto; in twikiForm */
}
.twikiForm h1,
.twikiForm h2,
.twikiForm h3,
.twikiForm h4,
.twikiForm h5,
.twikiForm h6 {
	margin-top:0;
}
.patternContent .twikiAttachments,
.patternContent .twikiForm {
	/* form or attachment table inside topic area */
	font-size:94%; /*S2*/
	padding:.5em 20px; /*S5*/ /* top:use less padding for the toggle link; bottom:use less space in case the table is folded in  */
	border-width:1px 0 0 0;
	border-style:solid;
	margin:0;
}
.twikiAttachments table,
table.twikiFormTable {
	margin:5px 0 10px 0; /* bottom:create extra space in case the table is folded out */
	border-collapse:collapse;
	padding:0px;
	border-spacing:0px;
	empty-cells:show;
	border-style:solid;
	border-width: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 td, 
.twikiAttachments th {
	border-style:solid;
	border-width:1px;
}
.twikiAttachments th,
table.twikiFormTable th.twikiFormTableHRow {
	padding:3px 6px;
	height:2.5em;
	vertical-align:middle;
}
table.twikiFormTable th.twikiFormTableHRow {
	text-align:center;
}
.twikiEditForm .twikiFormTable th,
.twikiEditForm .twikiFormTable td {
	padding:.25em .5em;
	vertical-align:middle;
	border-width:0 0 1px 0;
	border-style:solid;
}
.twikiAttachments th a:link,
.twikiAttachments th a:visited {
	text-decoration:none;
}
/* 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,
table.twikiFormTable td {
	padding:3px 6px;
	height:1.4em; /*S1*/
	text-align:left;
	vertical-align:top;
}
.twikiAttachments td {
	/* don't show column lines in attachment listing */
	border-width:0 0 1px 0;
}
.twikiAttachments th.twikiFirstCol,
.twikiAttachments td.twikiFirstCol {
	/* make more width for the icon column */
	width:26px;
	text-align:center;
}
.twikiAttachments caption {
	display:none;
}
table.twikiFormTable th.twikiFormTableHRow a:link,
table.twikiFormTable th.twikiFormTableHRow a:visited {
	text-decoration:none;
}

.twikiFormSteps {
	text-align:left;
	padding:.25em 0 0 0;
	border-width:1px 0;
	border-style:solid;
}
.twikiFormStep {
	line-height:140%;
	padding:1em 20px; /*S5*/
	border-width:0 0 1px 0;
	border-style:solid;
}
.twikiFormStep h3,
.twikiFormStep h4 {
	font-size:115%;
	border:none;
	margin:0;
	padding:0;
}
.twikiFormStep h3 {
	font-weight:bold;
}
.twikiFormStep h4 {
	font-weight:normal;
}
.twikiFormStep p {
	margin:.3em 0;
}

.twikiToc {
	margin:1em 0;
	padding:.3em 0 .6em 0;
}
.twikiToc ul {
	list-style:none;
	padding:0 0 0 .5em;
	margin:0em;
}
.twikiToc li {
	margin-left:1em;
	padding-left:1em;
	background-repeat:no-repeat;
	background-position:0 .5em;
}
.twikiToc .twikiTocTitle {
	margin:0em;
	padding:0em;
	font-weight:bold;
}

.twikiSmall {
	font-size:86%; line-height:110%; /*S3*/
}
.twikiSmallish {
	font-size:94%; /*S2*/
}
.twikiNew { }
.twikiSummary {
	font-size:86%; line-height:110%; /*S3*/
}
.twikiEmulatedLink {
	text-decoration:underline;
}
.twikiPageForm table {
	border-width:1px;
	border-style:solid;
}
.twikiPageForm table {
	width:100%;
	margin:0 0 2em 0;
}
.twikiPageForm th,
.twikiPageForm td {
	border:0;
	padding:.15em 1em;
}
.twikiPageForm td {}
.twikiPageForm td.first {
	padding-top:1em;
}
.twikiBroadcastMessage {
	padding:.25em .5em;
	margin:0 0 1em 0;
}
.twikiHelp {
	padding:1em;
	margin:0 0 1em 0;
	border-width:1px 0;
	border-style:solid;
}
.twikiHelp ul,
.twikiHelp li {
	margin:0;
}
.twikiHelp ul {
	padding-left:2em;
}
.twikiAccessKey {
	text-decoration:none;
	border-width:0 0 1px 0;
	border-style:solid;
}
a:hover .twikiAccessKey {
	text-decoration:none;
	border:none;
}
.twikiWebIndent {
	margin:0 0 0 1em;
}

a.twikiLinkInHeaderRight {
	float:right;
	display:block;
	margin:0 0 0 5px;
}

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

.patternTopic {
	margin:1em 0 2em 0;
}
#patternLeftBarContents {
	font-size:94%; /*S2*/
	padding:0 0 .5em 0;
}
#patternLeftBarContents a img {
	margin:1px 0 0 0;
}
#patternLeftBarContents a:link,
#patternLeftBarContents a:visited {
	text-decoration:none;
}
#patternLeftBarContents ul {
	padding:0;
	margin:.5em 0 1em 0;
	list-style:none;
}
#patternLeftBarContents li {
	width:100%;
	margin:0 1.1em 0 0;
	overflow:hidden;
}
#patternLeftBarContents .patternWebIndicator {
	margin:0 -1em; /*S6*/
	padding:.55em 1em; /*S6*/
	line-height:1.4em;
	text-align:center;
}
#patternLeftBarContents .patternWebIndicator a:link,
#patternLeftBarContents .patternWebIndicator a:visited {
	text-decoration:none;
}
#patternLeftBarContents .patternLeftBarPersonal {
	margin:0 -1em; /*S6*/
	padding:.55em 1em; /*S6*/
	width:100%;
	border-width:0 0 1px 0;
	border-style:solid;
}
#patternLeftBarContents .patternLeftBarPersonal ul {
	margin:0;
	padding:0;
}
#patternLeftBarContents .patternLeftBarPersonal li {
	padding-left:1em;
	background-repeat:no-repeat;
}
#patternLeftBarContents .patternLeftBarPersonal a:hover {
	text-decoration:none;
}


.patternTop {
	font-size:94%; /*S2*/
}
/* Button tool bar */
.patternToolBar {
	margin:.4em 0 0 0;
	padding:0 .5em 0 0;
	height:1%; /* for Win IE */
}
.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;
	/* relative + z-index removed due to buggy Win/IE redrawing problems */
	/*
	position:relative;
	z-index:0;
	*/
	padding:.15em .45em;
}
.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;
	z-index:2;
	clear:both;
}
.patternMetaMenu input,
.patternMetaMenu select,
.patternMetaMenu select option {
	font-size:.86em; /* use em instead of % for consistent size */
	margin:0;
	width:8em;
}
.patternMetaMenu select option {
	padding:1px 0 0 0;
}
.patternMetaMenu ul {
    padding:0;
    margin:0;
   	list-style:none;
}
.patternMetaMenu ul li {
    padding:0 .1em 0 .1em;
	display:inline;
}

/* breadcrumb */
.patternHomePath {
	font-size:94%; /*S2*/
	margin:.3em 0;
}
.patternHomePath a:link,
.patternHomePath a:visited {
	text-decoration:none;
}
.patternRevInfo {
	margin:0 0 0 .15em;
	font-size:94%;
}

.patternTopicAction {
	line-height:1.5em;
	padding:.4em 20px; /*S5*/
	border-width:1px 0;
	border-style:solid;
}
.patternViewPage .patternTopicAction {
	font-size:94%; /*S2*/
}
.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:1em 0;
}
.patternMoved i,
.patternMoved em {
	font-style:normal;
}

/* 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:20%;
	text-align:right;
}
table#twikiSearchTable td {
	width:80%;
}
table#twikiSearchTable td.first {
	padding:1em;
}

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

.patternSearchResults {
	/* no longer used in search.pattern.tmpl, but remains in rename templates */
	margin:0 0 1em 0;
}
.patternSearchResults blockquote {
	margin:1em 0 1em 5em;
}
h3.patternSearchResultsHeader,
h4.patternSearchResultsHeader {
	display:block;
	border-width:0 0 1px 0;
	border-style:solid;
	height:1%; /* or WIN/IE wont draw the backgound */
	font-weight:bold;
}
.patternSearchResults h3 {
	font-size:115%; /* same as twikiFormStep */
	margin:0;
	padding:.5em 20px;
	font-weight:bold;
}
h4.patternSearchResultsHeader {
	font-size:100%;
	padding-top:.3em;
	padding-bottom:.3em;
	font-weight:normal;
}
.patternSearchResult .twikiTopRow {
	padding-top:.2em;
}
.patternSearchResult .twikiBottomRow {
	padding-bottom:.25em;
	border-width:0 0 1px 0;
	border-style:solid;
}
.patternSearchResult .twikiAlert {
	font-weight:bold;
}
.patternSearchResult .twikiSummary .twikiAlert {
	font-weight:normal;
}
.patternSearchResult .twikiNew {
	border-width:1px;
	border-style:solid;
	font-size:85%; /*S3*/
	padding:0 1px;
	font-weight:bold;
}
.patternSearchResults .twikiHelp {
	display:block;
	width:auto;
	padding:.1em 5px;
	margin:1em -5px .35em -5px;
}
.patternSearchResult .twikiSRAuthor {
	width:15%;
	text-align:left;
}
.patternSearchResult .twikiSRRev {
	width:30%;
	text-align:left;
}
.patternSearchResultCount {
	margin:1em 0 3em 0;
}
.patternSearched {
}

/* Search results in book view format */

.patternBookView {
	border-width:0 0 2px 2px;
	border-style:solid;
	/* border color in cssdynamic.pattern.tmpl */
	margin:.5em 0 1.5em -5px;
	padding:0 0 0 5px;
}
.patternBookView .twikiTopRow {
	padding:.25em 5px .15em 5px; /*S4*/
	margin:1em -5px .15em -5px; /*S4*/
}
.patternBookView .twikiBottomRow {
	font-size:100%;
	padding:1em 0 1em 0;
	width:auto;
	border:none;
}

/* pages that are not view */

.patternNoViewPage #patternMainContents {
	padding-top:1.5em;
}


/* oopsmore.pattern.tmpl */

table.patternDiffOptions {
	margin:.5em 0;
	border:none;
}
table.patternDiffOptions td {
	border:none;
	text-align:center;
}
table.patternDiffOptions img {
	padding:0 10px;
	border-width:1px;
	border-style:solid;
}

/* edit.pattern.tmpl */

.patternEditPage .twikiForm h1,
.patternEditPage .twikiForm h2,
.patternEditPage .twikiForm h3 {
	/* same as twikiFormStep */
	font-size:120%;
	font-weight:bold;
}	
.twikiEditboxStyleMono {
	font-family:"Courier New", courier, monaco, monospace;
}
.twikiEditboxStyleProportional {
	font-family:"Lucida Grande", verdana, arial, sans-serif;
}
.twikiChangeFormButtonHolder {
	margin:.5em 0;
	float:right;
}
.twikiChangeFormButton .twikiButton,
.twikiChangeFormButtonHolder .twikiButton {
	padding:0em;
	margin:0em;
	border:none;
	text-decoration:underline;
	font-weight:normal;
}
.patternFormHolder { /* constrains the textarea */
	width:100%;
}
.patternSigLine {
	margin:.25em 0 .5em 0;
	padding:0 .5em 0 0;
}
.patternAccessKeyInfo {
	margin:1em 0 .5em 0;
	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.pattern.tmpl */

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

/* attach.pattern.tmpl */

.patternAttachPage .twikiAttachments table {
	width:auto;
}
.patternAttachPage .patternTopicAction {
	margin-top:-1px;
}
.patternAttachPage .twikiAttachments {
	margin-top:0;
}
.patternAttachForm {
	margin:0 0 3.5em 0;
}
.patternMoveAttachment {
	margin:.5em 0 0 0;
	text-align:right;
}

/* rdiff.pattern.tmpl */

.patternDiff {
	/* same as patternBookView */
	border-width:0 0 2px 2px;
	border-style:solid;
	margin:.5em 0 1.5em -5px;
	padding:0 0 0 5px;
}
.patternDiffPage .patternRevInfo ul {
	padding:0;
	margin:2em 0 0 0;
	list-style:none;
}
.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)			#ECF4FB
	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
	BG13 light blue: form steps														#F6FAFD
	BG14 lighter blue: left bar														#F9FCFE
	
	Border colors
	----------------------------------------
	BO1	light gray																	#efefef
	BO2 submit button border blue ('active')										#88B6CF
	BO3	info light blue border														#D5E6F3
	BO4 border color beige, header h2 bottom border									#E2DCC8
	BO5 header h3..h6 bottom border	(75% of BO4)									#E9E4D2
	BO6 darker gray																	#aaa
	BO7 neutral gray border															#ccc
	BO8 light neutral gray															#ddd
	BO9 alert border																#f00
	BO10 dark gray (same as BG11)													#8E9195

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

/* LAYOUT ELEMENTS */

#patternTopBar{
	background-color:#fff;
	border-color:#ccc;
}
#patternMain { /* don't set a background here; use patternOuter */ }
#patternOuter {
	background-color:#fff; /*** Sets background of center col***/
	border-color:#ccc;
}
#patternLeftBar, #patternLeftBarContents { /* don't set a background here; use patternWrapper */ }
#patternWrapper {
	background-color:#F6FAFD; /*BG13*/
}
#patternBottomBar {
	background-color:#fff;
	border-color:#ccc;
}
#patternBottomBarContents,
#patternBottomBarContents a:link,
#patternBottomBarContents a:visited {
	color:#8E9195;	/*T8*/
}

/* GENERAL HTML ELEMENTS */

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; /*BO7*/
	background-color:#ccc; /*BO7*/
}
pre, code, tt {
	color:#7A4707; /*T6*/
}
h1, h2, h3, h4, h5, h6 {
	color:#a00; /*T5*/
}
h1 a:link,
h1 a:visited {
	color:#a00; /*T5*/
}
h1 a:hover {
	color:#FBF7E8; /*T3*/
}
h2 {
	background-color:#FDFAF1;
	border-color:#E2DCC8; /*BO4*/
}
h3, h4, h5, h6 {
	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:#ddd; /*BO8*/
}
.twikiNewLink a:hover sup {
	background-color:#D6000F; /*BG2*/
	color:#FBF7E8; /*C3*/
	border-color:#D6000F; /*BG2*/ /* (part of bg) */
}
.twikiNewLink {
	border-color:#ddd; /*BO8*/
}
: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*/
}

/* Form elements */

textarea,
input,
select {
	border-color:#aaa; /*BO6*/
}
.twikiSubmit,
.twikiButton {
	border-color:#ddd #aaa #aaa #ddd;
	color:#333;
	background-color:#fff; /*BG1*/
}
.twikiSubmit:active,
.twikiButton:active {
	border-color:#999 #ccc #ccc #999;
	color:#000;
}
.twikiInputField,
.twikiSelect {
	border-color:#aaa #ddd #ddd #aaa;
	color:#000;
	background-color:#fff; /*BG1*/
}

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

/* TablePlugin */
.twikiTable,
.twikiTable td,
.twikiTable th {
	border-color:#ccc; /*BO8*/
}
.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,
th.twikiSortedDescendingCol a:link,
th.twikiSortedDescendingCol a:link font,
th.twikiSortedDescendingCol a:visited,
th.twikiSortedDescendingCol a:visited font {
	border-color:#666; /*T7*/
}
th.twikiSortedAscendingCol a:hover,
th.twikiSortedAscendingCol a:hover font,
th.twikiSortedDescendingCol a:hover,
th.twikiSortedDescendingCol a:hover font {
	border-color:#D6000F; /*T4*/
}

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

/* TipsContrib */
.tipsOfTheDay {
	background-color:#ECF4FB; /*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 {
	color:#8E9195; /*T8*/
}
.twikiGrayText a:link,
.twikiGrayText a:visited {
	color:#8E9195; /*T8*/
}
.twikiGrayText a:hover {
	color:#FBF7E8; /*C3*/
}

table.twikiFormTable th.twikiFormTableHRow,
table.twikiFormTable td.twikiFormTableRow {
	color:#666; /*T7*/
}
.twikiEditForm {
	color:#000; /*T1*/
}
.twikiEditForm .twikiFormTable th,
.twikiEditForm .twikiFormTable td {
	border-color:#ddd; /*BO8*/
}
.twikiEditForm .twikiFormTable td  {
	background-color:#F6F8FC;
}
.twikiEditForm .twikiFormTable th {
	background-color:#ECF4FB; /*BG5*/
}
.patternContent .twikiAttachments,
.patternContent .twikiForm {
	background-color:#FEFBF3; /*BG9*/
	border-color:#E2DCC8; /*BO4*/
}
.twikiAttachments table,
table.twikiFormTable {
	border-color:#ccc; /*BO7*/
	background-color:#fff; /*BG1*/
}
.twikiAttachments table {
	background-color:#fff; /*BG1*/
}
.twikiAttachments td, 
.twikiAttachments th {
	border-color:#ccc;
}
.twikiAttachments th/*,
table.twikiFormTable th.twikiFormTableHRow*/ {
	background-color:#fff; /*BG1*/
}
.twikiAttachments td {
	background-color:#fff; /*BG1*/
}
.twikiAttachments th a:link,
.twikiAttachments th a:visited,
table.twikiFormTable th.twikiFormTableHRow a:link,
table.twikiFormTable th.twikiFormTableHRow a:visited {
	color:#06c; /*T2*/
}
.twikiAttachments th font,
table.twikiFormTable th.twikiFormTableHRow font {
	color:#06c; /*T2*/
}
.twikiAttachments th a:hover,
table.twikiFormTable th.twikiFormTableHRow a:hover {
	border-color:#06c; /*T2*/
	background-color:transparent;
}
.twikiAttachments th.twikiSortedAscendingCol,
.twikiAttachments th.twikiSortedDescendingCol {
	background-color:#efefef; /*BG3*/
}
.twikiFormSteps {
	background-color:#F6FAFD; /*BG13*/
	border-color:#E2DCC8;
}
.twikiFormStep {
	border-color:#E2DCC8;
}
.twikiFormStep h3,
.twikiFormStep h4 {
	background-color:transparent;
}
.twikiToc .twikiTocTitle {
	color:#666; /*T7*/
}
.twikiBroadcastMessage {
	background-color:yellow;
}
.twikiBroadcastMessage b,
.twikiBroadcastMessage strong {
	color:#f00; /*T9*/
}
.twikiAlert,
.twikiAlert code {
	color:#f00; /*T9*/
}
.twikiEmulatedLink {
	color:#06c; /*T2*/
}
.twikiPageForm table {
	border-color:#ddd; /*BO8*/
	background:#fff; /*BG1*/
}
.twikiPageForm hr {
	border-color:#efefef; /*BO1*/
	background-color:#efefef; /*BO1*/
	color:#efefef; /*BO1*/
}
.twikiHelp {
	background-color:#ECF4FB; /*BG5*/
	border-color:#D5E6F3; /*BO3*/
}
.twikiAccessKey {
	color:inherit;
	border-color:#8E9195; /*T8*/
}
a:link .twikiAccessKey,
a:visited .twikiAccessKey,
a:hover .twikiAccessKey {
	color:inherit;
}


/*	-----------------------------------------------------------
	Pattern skin specific elements
	-----------------------------------------------------------	*/
#patternPage {
	background-color:#fff; /*BG1*/
}
/* Left bar */
#patternLeftBarContents {
	color:#666; /*T7*/
}
#patternLeftBarContents .patternWebIndicator {
	color:#000; /*T1*/
}
#patternLeftBarContents .patternWebIndicator a:link,
#patternLeftBarContents .patternWebIndicator a:visited {
	color:#000; /*T1*/
}
#patternLeftBarContents .patternWebIndicator a:hover {
	color:#FBF7E8; /*T3*/
}
#patternLeftBarContents hr {
	color:#E2DCC8; /*BO4*/
	background-color:#E2DCC8; /*BO4*/
}
#patternLeftBarContents a:link,
#patternLeftBarContents a:visited {
	color:#7A4707; /*T6*/
}
#patternLeftBarContents a:hover {
	color:#FBF7E8; /*C3*/
}
#patternLeftBarContents b,
#patternLeftBarContents strong {
	color:#333; /*T11*/
}
#patternLeftBarContents .patternChangeLanguage {
	color:#8E9195; /*T8*/
}
#patternLeftBarContents .patternLeftBarPersonal {
	border-color:#D9EAF6;
}
#patternLeftBarContents .patternLeftBarPersonal a:link,
#patternLeftBarContents .patternLeftBarPersonal a:visited {
	color:#06c; /*T2*/;
}
#patternLeftBarContents .patternLeftBarPersonal a:hover {
	color:#FBF7E8; /*C3*/
	background-color:#D6000F; /*BG2*/
}

.patternSeparator {
	font-family:monospace;
}
.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*/
}
.patternFormFieldDefaultColor {
	/* input fields default text color (no user input) */
	color:#8E9195; /*T8*/
}

.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:#ccc;
	border-color:#e0e0e0;
	background-color:#fff; /*BG1*/
}
.patternToolBar .patternButton a:hover {
	background-color:#D6000F; /*BG2*/
	color:#FBF7E8; /*C3*/
	border-color:#D6000F; /*T4*/
}
.patternToolBar .patternButton img {
	background-color:transparent;
}	
.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;
}

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

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

/* WebSearch, WebSearchAdvanced */
table#twikiSearchTable th,
table#twikiSearchTable td {
	background-color:#fff; /*BG1*/
	border-color:#ddd; /*BO8*/
} 
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
	-----------------------------------------------------------	*/

h3.patternSearchResultsHeader,
h4.patternSearchResultsHeader {
	background-color:#FEFBF3; /*BG9*/
	border-color:#ccc; /*BO7*/
}
h4.patternSearchResultsHeader {
	color:#000;
}
.patternNoViewPage h4.patternSearchResultsHeader {
	color:#a00; /*T5*/
}
.patternSearchResult .twikiBottomRow {
	border-color:#ddd; /*BO8*/
}
.patternSearchResult .twikiAlert {
	color:#f00; /*T9*/
}
.patternSearchResult .twikiSummary .twikiAlert {
	color:#900; /*C5*/
}
.patternSearchResult .twikiNew {
	background-color:#ECFADC; /*BG10*/
	border-color:#049804; /*T10*/
	color:#049804; /*T10*/
}
.patternViewPage .patternSearchResultsBegin {
	border-color:#ddd; /*BO8*/
}

/* Search results in book view format */

.patternBookView .twikiTopRow {
	background-color:transparent; /* set to WEBBGCOLOR in css.pattern.tmpl */
	color:#666; /*T7*/
}
.patternBookView .twikiBottomRow {
	border-color:#ddd; /*BO8*/
}
.patternBookView .patternSearchResultCount {
	color:#8E9195; /*T8*/
}

/* oopsmore.pattern.tmpl */

table.patternDiffOptions img {
	border-color:#ccc; /*BO7*/
}

/* edit.pattern.tmpl */

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

/* preview.pattern.tmpl */

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

/* rdiff.pattern.tmpl */

.patternDiff {
	border-color:#ccc;
}
.patternDiff h4.patternSearchResultsHeader {
	background-color:#ccc;
}
tr.twikiDiffDebug td {
	border-color:#ddd; /*BO8*/
}
.patternDiffPage .twikiDiffTable th {
	background-color:#eee;
}
tr.twikiDiffDebug .twikiDiffChangedText,
tr.twikiDiffDebug .twikiDiffChangedText {
	background:#99ff99; /* green */
}
/* 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:#ccc;
}
/* Unchanged */
.twikiDiffUnchangedTextContents { }
.twikiDiffLineNumberHeader {
	background-color:#eee;
}


/* CONFIGURE SPECIFIC */

#twikiPassword,
#twikiPasswordChange {
	width:40em;
	margin:1em auto;
	text-align:center;
}
#twikiPassword .twikiFormSteps,
#twikiPasswordChange .twikiFormSteps {
	border-width:5px;
}

ul {
    margin-top:0;
    margin-bottom: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:#ECF4FB;
    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:#ECF4FB;
    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 ),
       ],
       -class => 'patternNoViewPage');

# 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 = "<div id=\"patternScreen\"><div id=\"patternPageShadow\"><div id=\"patternPage\"><div id=\"patternOuter\"><div id=\"patternFloatWrap\"><div id=\"patternMain\"><div id=\"patternMainContents\">";
$body .= CGI::img({src=>$ENV{SCRIPT_NAME}.'?action=image;image=T-logo-140x40-t.gif;type=image/gif', class=>'logo', alt=>'TWiki', width=>'140', height=>'40'});
$body .= CGI::h1( 'Configuration');
$body .= "<div class=\"patternContent\"><div class=\"patternTopic\">";

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({height=>'16', width=>'16', 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();
    }
}
$body .= "</div><!--/patternTopic--></div><!--/patternContent--></div><!--/patternMainContents--></div><!--/patternMain-->
</div><!--/patternFloatWrap--><div class=\"clear\">&nbsp;</div>
</div><!--/patternOuter--></div><!--/patternPage--></div><!--/patternPageShadow--></div><!--/patternScreen-->";
print $body;
print CGI::end_html();
1;
