Index: theme/standard/config.php
===================================================================
RCS file: /cvsroot/moodle/moodle/theme/standard/config.php,v
retrieving revision 1.27
diff -u -r1.27 config.php
--- theme/standard/config.php	6 May 2009 09:14:43 -0000	1.27
+++ theme/standard/config.php	25 Jun 2009 12:38:09 -0000
@@ -178,4 +178,12 @@
 /// added a block when anther theme was selected).
 ////////////////////////////////////////////////////////////////////////////////
 
-?>
+
+$THEME->rendererfactory = 'standard_renderer_factory';
+/// This is an advanced features that lets you control the HTML that Moodle
+/// generates. You need to specify a class that implements the renderer_factory
+/// interface. As well as the default 'standard_renderer_factory', there is
+/// also the experimental 'template_renderer_factory', or you could implement
+/// your own. For more information, please see
+/// http://docs.moodle.org/en/Developement:How_Moodle_outputs_HTML
+////////////////////////////////////////////////////////////////////////////////
Index: lib/weblib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/weblib.php,v
retrieving revision 1.1276
diff -u -r1.1276 weblib.php
--- lib/weblib.php	24 Jun 2009 22:34:29 -0000	1.1276
+++ lib/weblib.php	25 Jun 2009 12:38:08 -0000
@@ -2329,33 +2329,12 @@
     return ($direction.' lang="'.$language.'" xml:lang="'.$language.'"');
 }
 
-/**
- * Return the markup for the destination of the 'Skip to main content' links.
- * Accessibility improvement for keyboard-only users.
- *
- * Used in course formats, /index.php and /course/index.php
- *
- * @return string HTML element.
- */
-function skip_main_destination() {
-    return '<span id="maincontent"></span>';
-}
-
 
 /// STANDARD WEB PAGE PARTS ///////////////////////////////////////////////////
 
 /**
  * Print a standard header
  *
- * @global object
- * @global object
- * @global object
- * @global object
- * @global string Doesnt appear to be used here
- * @global string Doesnt appear to be used here
- * @global object
- * @global object
- * @uses $_SERVER
  * @param string  $title Appears at the top of the window
  * @param string  $heading Appears at the top of the page
  * @param string  $navigation Array of $navlinks arrays (keys: name, link, type) for use as breadcrumbs links
@@ -2369,7 +2348,7 @@
  * @param bool    $return If true, return the visible elements of the header instead of echoing them.
  * @return string|void If return=true then string else void
  */
-function print_header ($title='', $heading='', $navigation='', $focus='',
+function print_header_old($title='', $heading='', $navigation='', $focus='',
                        $meta='', $cache=true, $button='&nbsp;', $menu='',
                        $usexml=false, $bodytags='', $return=false) {
 
@@ -2728,7 +2707,7 @@
  * @param boolean $return output as string
  * @return mixed string or void
  */
-function print_footer($course=NULL, $usercourse=NULL, $return=false) {
+function print_footer_old($course=NULL, $usercourse=NULL, $return=false) {
     global $USER, $CFG, $THEME, $COURSE, $SITE, $PAGE;
 
     if (defined('ADMIN_EXT_HEADER_PRINTED') and !defined('ADMIN_EXT_FOOTER_PRINTED')) {
@@ -3062,7 +3041,7 @@
             $mods = get_plugin_list('mod');
             foreach ($mods as $mod => $moddir) {
                 if (file_exists($moddir.'/styles.php')) {
-                    $files[] = array($moddir.'/styles.php');
+                    $files[] = array('', $moddir.'/styles.php');
                 }
             }
         }
@@ -3071,7 +3050,7 @@
             $mods = get_plugin_list('blocks');
             foreach ($mods as $mod => $moddir) {
                 if (file_exists($moddir.'/styles.php')) {
-                    $files[] = array($moddir.'/styles.php');
+                    $files[] = array('', $moddir.'/styles.php');
                 }
             }
         }
@@ -3080,7 +3059,7 @@
             $mods = get_plugin_list('format');
             foreach ($mods as $mod => $moddir) {
                 if (file_exists($moddir.'/styles.php')) {
-                    $files[] = array($moddir.'/styles.php');
+                    $files[] = array('', $moddir.'/styles.php');
                 }
             }
         }
@@ -3089,7 +3068,7 @@
             $reports = get_plugin_list('gradereport');
             foreach ($reports as $report => $reportdir) {
                 if (file_exists($reportdir.'/styles.php')) {
-                    $files[] = array($reportdir.'/styles.php');
+                    $files[] = array('', $reportdir.'/styles.php');
                 }
             }
         }
@@ -3225,10 +3204,6 @@
         $CFG->modpixpath = $CFG->themewww .'/'. $theme .'/pix/mod';
     }
 
-/// Header and footer paths
-    $CFG->header = $CFG->themedir .'/'. $theme .'/header.html';
-    $CFG->footer = $CFG->themedir .'/'. $theme .'/footer.html';
-
 /// Define stylesheet loading order
     $CFG->stylesheets = array();
     if ($theme != 'standard') {    /// The standard sheet is always loaded first
@@ -3335,7 +3310,31 @@
         $loggedinas = get_string('loggedinnot', 'moodle').
                       " (<a $CFG->frametarget href=\"$loginurl\">".get_string('login').'</a>)';
     }
-    return '<div class="logininfo">'.$loggedinas.'</div>';
+
+    $loggedinas = '<div class="logininfo">'.$loggedinas.'</div>';
+
+    if (isset($SESSION->justloggedin)) {
+        unset($SESSION->justloggedin);
+        if (!empty($CFG->displayloginfailures)) {
+            if (!empty($USER->username) and $USER->username != 'guest') {
+                if ($count = count_login_failures($CFG->displayloginfailures, $USER->username, $USER->lastlogin)) {
+                    $loggedinas .= '&nbsp;<div class="loginfailures">';
+                    if (empty($count->accounts)) {
+                        $loggedinas .= get_string('failedloginattempts', '', $count);
+                    } else {
+                        $loggedinas .= get_string('failedloginattemptsall', '', $count);
+                    }
+                    if (has_capability('coursereport/log:view', get_context_instance(CONTEXT_SYSTEM))) {
+                        $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php'.
+                                             '?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
+                    }
+                    $loggedinas .= '</div>';
+                }
+            }
+        }
+    }
+
+    return $loggedinas;
 }
 
 /**
@@ -3743,70 +3742,6 @@
     return(array('newnav' => true, 'navlinks' => $navigation));
 }
 
-
-/**
- * Prints a string in a specified size  (retained for backward compatibility)
- *
- * @param string $text The text to be displayed
- * @param int $size The size to set the font for text display.
- * @param bool $return If set to true output is returned rather than echoed Default false
- * @return string|void String if return is true
- */
-function print_headline($text, $size=2, $return=false) {
-    $output = print_heading($text, '', $size, true);
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-/**
- * Prints text in a format for use in headings.
- *
- * @global string Apparently not used in this function
- * @uses CLI_SCRIPT
- * @param string $text The text to be displayed
- * @param string $align The alignment of the printed paragraph of text
- * @param int $size The size to set the font for text display.
- * @param string $class
- * @param bool $return If set to true output is returned rather than echoed, default false
- * @param string $id The id to use in the element
- * @return string|void String if return=true nothing otherwise
- */
-function print_heading($text, $align='', $size=2, $class='main', $return=false, $id='') {
-    global $verbose;
-    if ($align) {
-        $align = ' style="text-align:'.$align.';"';
-    }
-    if ($class) {
-        $class = ' class="'.$class.'"';
-    }
-    if ($id) {
-        $id = ' id="'.$id.'"';
-    }
-    if (!CLI_SCRIPT) {
-        $output = "<h$size $align $class $id>".$text."</h$size>";
-    } else {
-        $output = $text;
-        if ($size == 1) {
-            $output = '=>'.$output;
-        } else if ($size == 2) {
-            $output = '-->'.$output;
-        }
-    }
-
-    if ($return) {
-        return $output;
-    } else {
-        if (!CLI_SCRIPT) {
-            echo $output;
-        } else {
-            echo $output."\n";
-        }
-    }
-}
-
 /**
  * Centered heading with attached help button (same title text)
  * and optional icon attached
@@ -3832,132 +3767,6 @@
 }
 
 /**
- * Output a standard heading block
- *
- * @param string $heading The text to write into the heading
- * @param string $class An additional Class Attr to use for the heading
- * @param bool $return If set to true output is returned rather than echoed, default false
- * @return string|void HTML String if return=true nothing otherwise
- */
-function print_heading_block($heading, $class='', $return=false) {
-    //Accessibility: 'headingblock' is now H1, see theme/standard/styles_*.css: ??
-    $output = '<h2 class="headingblock header '.$class.'">'.$heading.'</h2>';
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-
-/**
- * Print a link to continue on to another page.
- *
- * @global object
- * @uses $_SERVER
- * @param string $link The url to create a link to.
- * @param bool $return If set to true output is returned rather than echoed, default false
- * @return string|void HTML String if return=true nothing otherwise
- */
-function print_continue($link, $return=false) {
-
-    global $CFG;
-
-    $output = '';
-
-    if ($link == '') {
-        if (!empty($_SERVER['HTTP_REFERER'])) {
-            $link = $_SERVER['HTTP_REFERER'];
-            $link = str_replace('&', '&amp;', $link); // make it valid XHTML
-        } else {
-            $link = $CFG->wwwroot .'/';
-        }
-    }
-
-    $options = array();
-    $linkparts = parse_url(str_replace('&amp;', '&', $link));
-    if (isset($linkparts['query'])) {
-        parse_str($linkparts['query'], $options);
-    }
-
-    $output .= '<div class="continuebutton">';
-
-    $output .= print_single_button($link, $options, get_string('continue'), 'get', $CFG->framename, true);
-    $output .= '</div>'."\n";
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-
-/**
- * Print a message in a standard themed box.
- * Replaces print_simple_box (see deprecatedlib.php)
- *
- * @param string $message, the content of the box
- * @param string $classes, space-separated class names.
- * @param string $ids
- * @param boolean $return, return as string or just print it
- * @return string|void mixed string or void
- */
-function print_box($message, $classes='generalbox', $ids='', $return=false) {
-
-    $output  = print_box_start($classes, $ids, true);
-    $output .= $message;
-    $output .= print_box_end(true);
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-/**
- * Starts a box using divs
- * Replaces print_simple_box_start (see deprecatedlib.php)
- *
- * @global object
- * @param string $classes, space-separated class names.
- * @param string $ids
- * @param boolean $return, return as string or just print it
- * @return string|void  string or void
- */
-function print_box_start($classes='generalbox', $ids='', $return=false) {
-    global $THEME;
-
-    if (strpos($classes, 'clearfix') !== false) {
-        $clearfix = true;
-        $classes = trim(str_replace('clearfix', '', $classes));
-    } else {
-        $clearfix = false;
-    }
-
-    if (!empty($THEME->customcorners)) {
-        $classes .= ' ccbox box';
-    } else {
-        $classes .= ' box';
-    }
-
-    return print_container_start($clearfix, $classes, $ids, $return);
-}
-
-/**
- * Simple function to end a box (see above)
- * Replaces print_simple_box_end (see deprecatedlib.php)
- *
- * @param boolean $return, return as string or just print it
- * @return string|void Depending on value of return
- */
-function print_box_end($return=false) {
-    return print_container_end($return);
-}
-
-/**
  * Print (or return) a collapisble region, that has a caption that can
  * be clicked to expand or collapse the region.
  * 
@@ -4052,107 +3861,6 @@
 }
 
 /**
- * Print a message in a standard themed container.
- *
- * @param string $message, the content of the container
- * @param boolean $clearfix clear both sides
- * @param string $classes, space-separated class names.
- * @param string $idbase
- * @param boolean $return, return as string or just print it
- * @return string|void Depending on value of $return
- */
-function print_container($message, $clearfix=false, $classes='', $idbase='', $return=false) {
-
-    $output  = print_container_start($clearfix, $classes, $idbase, true);
-    $output .= $message;
-    $output .= print_container_end(true);
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-/**
- * Starts a container using divs
- *
- * @global object
- * @param boolean $clearfix clear both sides
- * @param string $classes, space-separated class names.
- * @param string $idbase
- * @param boolean $return, return as string or just print it
- * @return string|void Based on value of $return
- */
-function print_container_start($clearfix=false, $classes='', $idbase='', $return=false) {
-    global $THEME;
-
-    if (!isset($THEME->open_containers)) {
-        $THEME->open_containers = array();
-    }
-    $THEME->open_containers[] = $idbase;
-
-
-    if (!empty($THEME->customcorners)) {
-        $output = _print_custom_corners_start($clearfix, $classes, $idbase);
-    } else {
-        if ($idbase) {
-            $id = ' id="'.$idbase.'"';
-        } else {
-            $id = '';
-        }
-        if ($clearfix) {
-            $clearfix = ' clearfix';
-        } else {
-            $clearfix = '';
-        }
-        if ($classes or $clearfix) {
-            $class = ' class="'.$classes.$clearfix.'"';
-        } else {
-            $class = '';
-        }
-        $output = '<div'.$id.$class.'>';
-    }
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-/**
- * Simple function to end a container (see above)
- *
- * @global object
- * @uses DEBUG_DEVELOPER
- * @param boolean $return, return as string or just print it
- * @return string|void Based on $return
- */
-function print_container_end($return=false) {
-    global $THEME;
-
-    if (empty($THEME->open_containers)) {
-        debugging('Incorrect request to end container - no more open containers.', DEBUG_DEVELOPER);
-        $idbase = '';
-    } else {
-        $idbase = array_pop($THEME->open_containers);
-    }
-
-    if (!empty($THEME->customcorners)) {
-        $output = _print_custom_corners_end($idbase);
-    } else {
-        $output = '</div>';
-    }
-
-    if ($return) {
-        return $output;
-    } else {
-        echo $output;
-    }
-}
-
-/**
  * Returns number of currently open containers
  *
  * @global object
@@ -5682,207 +5390,6 @@
 }
 
 /**
- * Print an error page displaying an error message.  New method - use this for new code.
- *
- * @global object
- * @global object
- * @param string $errorcode The name of the string from error.php to print
- * @param string $module name of module
- * @param string $link The url where the user will be prompted to continue. If no url is provided the user will be directed to the site index page.
- * @param object $a Extra words and phrases that might be required in the error string
- * @return void terminates script, does not return!
- */
-function print_error($errorcode, $module='error', $link='', $a=NULL) {
-    global $CFG, $UNITTEST;
-
-    // If unittest running, throw exception instead
-    if (!empty($UNITTEST->running)) {
-        // Errors in unit test become exceptions, so you can unit test
-        // code that might call error().
-        throw new moodle_exception($errorcode, $module, $link, $a);
-    }
-
-    if (empty($module) || $module == 'moodle' || $module == 'core') {
-        $module = 'error';
-    }
-
-    if (!isset($CFG->theme) or !isset($CFG->stylesheets)) {
-        // error found before setup.php finished
-        _print_early_error($errorcode, $module, $a);
-    } else {
-        _print_normal_error($errorcode, $module, $a, $link, debug_backtrace());
-    }
-}
-
-/**
- * Internal function - do not use directly!!
- *
- * @global object
- * @global object
- * @global object
- * @global object
- * @global object
- * @param string $errorcode
- * @param string $module
- * @param string $a
- * @param string $link
- * @param array $backtrace
- * @param string $debuginfo
- * @param bool $showerrordebugwarning
- * @return void Script dies no return
- */
-function _print_normal_error($errorcode, $module, $a, $link, $backtrace, $debuginfo=null, $showerrordebugwarning=false) {
-    global $CFG, $SESSION, $THEME, $DB, $PAGE;
-
-    if ($DB) {
-        //if you enable db debugging and exception is thrown, the print footer prints a lot of rubbish
-        $DB->set_debug(0);
-    }
-
-    if ($module === 'error') {
-        $modulelink = 'moodle';
-    } else {
-        $modulelink = $module;
-    }
-
-    $message = get_string($errorcode, $module, $a);
-    if ($module === 'error' and strpos($message, '[[') === 0) {
-        //search in moodle file if error specified - needed for backwards compatibility
-        $message = get_string($errorcode, 'moodle', $a);
-    }
-
-    if (CLI_SCRIPT) {
-        echo("!!! $message !!!\n");
-        if (debugging('', DEBUG_DEVELOPER)) {
-            if ($debuginfo) {
-                debugging($debuginfo, DEBUG_DEVELOPER, $backtrace);
-            } else {
-                notify('Stack trace:'.print_backtrace($backtrace, true, true), 'notifytiny');
-            }
-        }
-        exit(1); // general error code
-    }
-
-    if (empty($link) and !defined('ADMIN_EXT_HEADER_PRINTED')) {
-        if ( !empty($SESSION->fromurl) ) {
-            $link = $SESSION->fromurl;
-            unset($SESSION->fromurl);
-        } else {
-            $link = $CFG->wwwroot .'/';
-        }
-    }
-
-    if (!empty($CFG->errordocroot)) {
-        $errordocroot = $CFG->errordocroot;
-    } else if (!empty($CFG->docroot)) {
-        $errordocroot = $CFG->docroot;
-    } else {
-        $errordocroot = 'http://docs.moodle.org';
-    }
-
-    if (!$PAGE->headerprinted) {
-        //header not yet printed
-        @header('HTTP/1.0 404 Not Found');
-        print_header(get_string('error'));
-    } else {
-        print_container_end_all(false, $THEME->open_header_containers);
-    }
-
-    echo '<br />';
-
-    $message = clean_text('<p class="errormessage">'.$message.'</p>'.
-               '<p class="errorcode">'.
-               '<a href="'.$errordocroot.'/en/error/'.$modulelink.'/'.$errorcode.'">'.
-                 get_string('moreinformation').'</a></p>');
-
-    print_simple_box($message, '', '', '', '', 'errorbox');
-
-    if ($showerrordebugwarning) {
-        debugging('error() is a deprecated function, please call print_error() instead of error()', DEBUG_DEVELOPER);
-
-    } else {
-        if (debugging('', DEBUG_DEVELOPER)) {
-            if ($debuginfo) {
-                debugging($debuginfo, DEBUG_DEVELOPER, $backtrace);
-            } else {
-                notify('Stack trace:'.print_backtrace($backtrace, false, true), 'notifytiny');
-            }
-        }
-    }
-
-    if (!empty($link)) {
-        print_continue($link);
-    }
-
-    print_footer();
-
-    for ($i=0;$i<512;$i++) {  // Padding to help IE work with 404
-        echo ' ';
-    }
-    exit(1); // general error code
-}
-
-/**
- * Internal function - do not use directly!!
- * This function is used if fatal error occures before the themes are fully initialised (eg. in lib/setup.php)
- *
- * @uses $_SERVER
- * @uses DEBUG_DEVELOPER
- * @param string $errorcode
- * @param string $module
- * @param string $a
- * @param string $link
- * @param array $backtrace
- * @param string $debuginfo
- * @return void Script dies does not return
- */
-function _print_early_error($errorcode, $module, $a, $backtrace=null, $debuginfo=null) {
-    $message = get_string($errorcode, $module, $a);
-    if ($module === 'error' and strpos($message, '[[') === 0) {
-        //search in moodle file if error specified - needed for backwards compatibility
-        $message = get_string($errorcode, 'moodle', $a);
-    }
-    $message = clean_text($message);
-
-    // In the name of protocol correctness, monitoring and performance
-    // profiling, set the appropriate error headers for machine comsumption
-    if (isset($_SERVER['SERVER_PROTOCOL'])) {
-        // Avoid it with cron.php. Note that we assume it's HTTP/1.x
-        @header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
-    }
-
-    // better disable any caching
-    @header('Content-Type: text/html; charset=utf-8');
-    @header('Cache-Control: no-store, no-cache, must-revalidate');
-    @header('Cache-Control: post-check=0, pre-check=0', false);
-    @header('Pragma: no-cache');
-    @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
-    @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
-
-    echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" '.get_html_lang().'>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<title>'.get_string('error').'</title>
-</head><body>
-<div style="margin-top: 6em; margin-left:auto; margin-right:auto; color:#990000; text-align:center; font-size:large; border-width:1px;
-    border-color:black; background-color:#ffffee; border-style:solid; border-radius: 20px; border-collapse: collapse;
-    width: 80%; -moz-border-radius: 20px; padding: 15px">
-'.$message.'
-</div>';
-    if (debugging('', DEBUG_DEVELOPER)) {
-        if ($debuginfo) {
-            debugging($debuginfo, DEBUG_DEVELOPER, $backtrace);
-        } else if ($backtrace) {
-            notify('Stack trace:'.print_backtrace($backtrace, false, true), 'notifytiny');
-        }
-    }
-
-    echo '</body></html>';
-    exit(1); // general error code
-}
-
-/**
  * Print an error to STDOUT and exit with a non-zero code. For commandline scripts.
  * Default errorcode is 1.
  *
@@ -6287,43 +5794,6 @@
 }
 
 /**
- * Print a bold message in an optional color.
- *
- * @global object
- * @uses CLI_SCRIPT
- * @param string $message The message to print out
- * @param string $style Optional style to display message text in
- * @param string $align Alignment option
- * @param bool $return whether to return an output string or echo now
- * @return string|bool Depending on $result 
- */
-function notify($message, $style='notifyproblem', $align='center', $return=false) {
-    global $DB;
-
-    if ($style == 'green') {
-        $style = 'notifysuccess';  // backward compatible with old color system
-    }
-
-    $message = clean_text($message);
-    if (!CLI_SCRIPT) {
-        $output = '<div class="'.$style.'" style="text-align:'. $align .'">'. $message .'</div>'."\n";
-    } else {
-        if ($style === 'notifysuccess') {
-            $output = '++'.$message.'++'."\n";
-        } else {
-            $output = '!!'.$message.'!!'."\n";
-        }
-    }
-
-    if ($return) {
-        return $output;
-    }
-
-    echo $output;
-}
-
-
-/**
  * Given an email address, this function will return an obfuscated version of it
  *
  * @param string $email The email address to obfuscate
@@ -6918,34 +6388,6 @@
     return $subtree;
 }
 
-
-/**
- * Returns a string containing a link to the user documentation for the current
- * page. Also contains an icon by default. Shown to teachers and admin only.
- *
- * @global object
- * @global object
- * @param string $text The text to be displayed for the link
- * @param string $iconpath The path to the icon to be displayed
- * @return string The link to user documentation for this current page
- */
-function page_doc_link($text='', $iconpath='') {
-    global $CFG, $PAGE;
-
-    if (empty($CFG->docroot) || during_initial_install()) {
-        return '';
-    }
-    if (!has_capability('moodle/site:doclinks', $PAGE->context)) {
-        return '';
-    }
-
-    $path = $PAGE->docspath;
-    if (!$path) {
-        return '';
-    }
-    return doc_link($path, $text, $iconpath);
-}
-
 /**
  * Returns the Moodle Docs URL in the users language
  *
@@ -7021,85 +6463,32 @@
  * @param array $backtrace use different backtrace
  * @return bool
  */
-function debugging($message='', $level=DEBUG_NORMAL, $backtrace=null) {
-
+function debugging($message = '', $level = DEBUG_NORMAL, $backtrace = null) {
     global $CFG;
 
-    if (empty($CFG->debug)) {
+    if (empty($CFG->debug) || $CFG->debug < $level) {
         return false;
     }
 
-    if ($CFG->debug >= $level) {
-        if ($message) {
-            if (!$backtrace) {
-                $backtrace = debug_backtrace();
-            }
-            $from = print_backtrace($backtrace, CLI_SCRIPT, true);
-            if (!isset($CFG->debugdisplay)) {
-                $CFG->debugdisplay = ini_get_bool('display_errors');
-            }
-            if ($CFG->debugdisplay) {
-                if (!defined('DEBUGGING_PRINTED')) {
-                    define('DEBUGGING_PRINTED', 1); // indicates we have printed something
-                }
-                notify($message . $from, 'notifytiny');
-            } else {
-                trigger_error($message . $from, E_USER_NOTICE);
-            }
-        }
-        return true;
+    if (!isset($CFG->debugdisplay)) {
+        $CFG->debugdisplay = ini_get_bool('display_errors');
     }
-    return false;
-}
 
-/**
- * Prints formatted backtrace
- *
- * @global object
- * @param array $callers backtrace array
- * @param bool $return return as string or print
- * @return string|bool Depending on $return
- */
-function print_backtrace($callers, $plaintext=false, $return=false) {
-    // do not use $CFG->dirroot because it might not be available in desctructors
-    $dirroot = dirname(dirname(__FILE__));
- 
-    if (empty($callers)) {
-        if ($return) {
-            return '';
-        } else {
-            return;
+    if ($message) {
+        if (!$backtrace) {
+            $backtrace = debug_backtrace();
         }
-    }
-
-    $from = $plaintext ? '' : '<ul style="text-align: left">';
-    foreach ($callers as $caller) {
-        if (!isset($caller['line'])) {
-            $caller['line'] = '?'; // probably call_user_func()
-        }
-        if (!isset($caller['file'])) {
-            $caller['file'] = 'unknownfile'; // probably call_user_func()
-        }
-        $from .= $plaintext ? '* ' : '<li>';
-        $from .= 'line ' . $caller['line'] . ' of ' . str_replace($dirroot, '', $caller['file']);
-        if (isset($caller['function'])) {
-            $from .= ': call to ';
-            if (isset($caller['class'])) {
-                $from .= $caller['class'] . $caller['type'];
-            }
-            $from .= $caller['function'] . '()';
-        } else if (isset($caller['exception'])) {
-            $from .= ': '.$caller['exception'].' thrown';
+        $from = format_backtrace($backtrace, CLI_SCRIPT);
+        if ($CFG->debugdisplay) {
+            if (!defined('DEBUGGING_PRINTED')) {
+                define('DEBUGGING_PRINTED', 1); // indicates we have printed something
+            }
+            notify($message . $from, 'notifytiny');
+        } else {
+            trigger_error($message . $from, E_USER_NOTICE);
         }
-        $from .= $plaintext ? "\n" : '</li>';
-    }
-    $from .= $plaintext ? '' : '</ul>';
-
-    if ($return) {
-        return $from;
-    } else {
-        echo $from;
     }
+    return true;
 }
 
 /**
Index: lib/pagelib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/pagelib.php,v
retrieving revision 1.123
diff -u -r1.123 pagelib.php
--- lib/pagelib.php	24 Jun 2009 09:17:56 -0000	1.123
+++ lib/pagelib.php	25 Jun 2009 12:38:04 -0000
@@ -39,16 +39,19 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @since Moodle 2.0
  *
+ * @property-read string $generaltype the general type of page this is. For example 'normal', 'popup', 'home'.
+ *      Allows the theme to display things differently, if it wishes to.
+ * @property-read string $title the title that should go in the <head> section of the HTML of this page.
+ * @property-read string $heading the main heading that should be displayed at the top of the <body>.
+ * @property-read string $cacheable defaults to true. Set to false to stop the page being cached at all.
  * @property-read page_requirements_manager $requires Tracks resources (for example required .css and .js files) required by this page.
- * @property-read xhtml_container_stack $opencontainers Tracks open XHTML tags. Helps us generate well-formed XML, even in the face of errors.
  */
 class moodle_page {
     /**#@+ Tracks the where we are in the generation of the page. */
     const STATE_BEFORE_HEADER = 0;
     const STATE_PRINTING_HEADER = 1;
     const STATE_IN_BODY = 2;
-    const STATE_PRINTING_FOOTER = 3;
-    const STATE_DONE = 4;
+    const STATE_DONE = 3;
     /**#@-*/
 
 /// Field declarations =========================================================
@@ -89,8 +92,14 @@
 
     protected $_bodyclasses = array();
 
+    protected $_title = '';
+
+    protected $_heading = '';
+
     protected $_pagetype = null;
 
+    protected $_generaltype = 'normal';
+
     protected $_subpage = '';
 
     protected $_docspath = null;
@@ -107,7 +116,7 @@
 
     protected $_othereditingcaps = array();
 
-    protected $_opencontainers = null;
+    protected $_cacheable = true;
 
     /**
      * This is simply to improve backwards compatability. If old code relies on
@@ -122,7 +131,7 @@
 /// methods, but instead use the $PAGE->x syntax.
 
     /**
-     * Please do not call this method directly, use the ->state syntax. @see __get().
+     * Please do not call this method directly, use the ->state syntax. {@link __get()}.
      * @return integer one of the STATE_... constants. You should not normally need
      * to use this in your code. It is indended for internal use by this class
      * and its friends like print_header, to check that everything is working as
@@ -133,7 +142,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->headerprinted syntax. @see __get().
+     * Please do not call this method directly, use the ->headerprinted syntax. {@link __get()}.
      * @return boolean has the header already been printed?
      */
     public function get_headerprinted() {
@@ -141,7 +150,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->course syntax. @see __get().
+     * Please do not call this method directly, use the ->course syntax. {@link __get()}.
      *
      * @global object
      * @return object the current course that we are inside - a row from the
@@ -157,7 +166,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->cm syntax. @see __get().
+     * Please do not call this method directly, use the ->cm syntax. {@link __get()}.
      * @return object the course_module that this page belongs to. Will be null
      * if this page is not within a module. This is a full cm object, as loaded
      * by get_coursemodule_from_id or get_coursemodule_from_instance,
@@ -168,7 +177,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->activityrecord syntax. @see __get().
+     * Please do not call this method directly, use the ->activityrecord syntax. {@link __get()}.
      * @return object the row from the activities own database table (for example
      * the forum or quiz table) that this page belongs to. Will be null
      * if this page is not within a module.
@@ -181,7 +190,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->activityname syntax. @see __get().
+     * Please do not call this method directly, use the ->activityname syntax. {@link __get()}.
      * @return string|null the The type of activity we are in, for example 'forum' or 'quiz'.
      * Will be null if this page is not within a module.
      */
@@ -193,7 +202,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->category syntax. @see __get().
+     * Please do not call this method directly, use the ->category syntax. {@link __get()}.
      * @return mixed the category that the page course belongs to. If there isn't one
      * (that is, if this is the front page course) returns null.
      */
@@ -207,7 +216,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->categories syntax. @see __get().
+     * Please do not call this method directly, use the ->categories syntax. {@link __get()}.
      * @return array an array of all the categories the page course belongs to,
      * starting with the immediately containing category, and working out to
      * the top-level category. This may be the empty array if we are in the
@@ -219,7 +228,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->context syntax. @see __get().
+     * Please do not call this method directly, use the ->context syntax. {@link __get()}.
      * @return object the main context to which this page belongs.
      */
     public function get_context() {
@@ -230,7 +239,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->pagetype syntax. @see __get().
+     * Please do not call this method directly, use the ->pagetype syntax. {@link __get()}.
      * @return string e.g. 'my-index' or 'mod-quiz-attempt'. Same as the id attribute on <body>.
      */
     public function get_pagetype() {
@@ -241,7 +250,16 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->subpage syntax. @see __get().
+     * Please do not call this method directly, use the ->generaltype syntax. {@link __get()}.
+     * @return string the general type of page this is. For example 'normal', 'popup', 'home'.
+     *      Allows the theme to display things differently, if it wishes to.
+     */
+    public function get_generaltype() {
+        return $this->_generaltype;
+    }
+
+    /**
+     * Please do not call this method directly, use the ->subpage syntax. {@link __get()}.
      * @return string|null The subpage identifier, if any.
      */
     public function get_subpage() {
@@ -249,7 +267,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->bodyclasses syntax. @see __get().
+     * Please do not call this method directly, use the ->bodyclasses syntax. {@link __get()}.
      * @return string the class names to put on the body element in the HTML.
      */
     public function get_bodyclasses() {
@@ -257,7 +275,23 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->docspath syntax. @see __get().
+     * Please do not call this method directly, use the ->title syntax. {@link __get()}.
+     * @return string the title that should go in the <head> section of the HTML of this page.
+     */
+    public function get_title() {
+        return $this->_title;
+    }
+
+    /**
+     * Please do not call this method directly, use the ->heading syntax. {@link __get()}.
+     * @return string the main heading that should be displayed at the top of the <body>.
+     */
+    public function get_heading() {
+        return $this->_heading;
+    }
+
+    /**
+     * Please do not call this method directly, use the ->docspath syntax. {@link __get()}.
      * @return string the path to the Moodle docs for this page.
      */
     public function get_docspath() {
@@ -269,7 +303,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->url syntax. @see __get().
+     * Please do not call this method directly, use the ->url syntax. {@link __get()}.
      * @return moodle_url the clean URL required to load the current page. (You
      * should normally use this in preference to $ME or $FULLME.)
      */
@@ -283,7 +317,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->blocks syntax. @see __get().
+     * Please do not call this method directly, use the ->blocks syntax. {@link __get()}.
      * @return blocks_manager the blocks manager object for this page.
      */
     public function get_blocks() {
@@ -300,7 +334,7 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->requires syntax. @see __get().
+     * Please do not call this method directly, use the ->requires syntax. {@link __get()}.
      * @return page_requirements_manager tracks the JavaScript, CSS files, etc. required by this page.
      */
     public function get_requires() {
@@ -312,15 +346,11 @@
     }
 
     /**
-     * Please do not call this method directly, use the ->opencontainers syntax. @see __get().
-     * @return xhtml_container_stack Tracks the open XHTML tags on this page.
+     * Please do not call this method directly, use the ->cacheable syntax. {@link __get()}.
+     * @return boolean can this page be cached by the user's browser.
      */
-    public function get_opencontainers() {
-        global $CFG;
-        if (is_null($this->_opencontainers)) {
-            $this->_opencontainers = new xhtml_container_stack();
-        }
-        return $this->_opencontainers;
+    public function get_cacheable() {
+        return $this->_cacheable;
     }
 
     /**
@@ -489,6 +519,17 @@
     }
 
     /**
+     * @param string $generaltype the general type of page this is. For example 'popup', 'home'.
+     * This properly defaults to 'normal', so you only need to call this function if
+     * you want something different. The exact range of supported page types is not
+     * strictly defined, this value is just passed to the theme. However, at the moment
+     * only 'normal', 'popup' amd 'home' are used.
+     */
+    public function set_generaltype($generaltype) {
+        $this->_generaltype = $generaltype;
+    }
+
+    /**
      * If context->id and pagetype are not enough to uniquely identify this page,
      * then you can set a subpage id as well. For example, the tags page sets
      * @param string $subpage an arbitrary identifier that, along with context->id
@@ -522,6 +563,22 @@
     }
 
     /**
+     * $param string $title the title that should go in the <head> section of the HTML of this page.
+     */
+    public function set_title($title) {
+        $title = format_string($title);
+        $title = str_replace('"', '&quot;', $title);
+        $this->_title = $title;
+    }
+
+    /**
+     * $param string $heading the main heading that should be displayed at the top of the <body>.
+     */
+    public function set_heading($heading) {
+        $this->_heading = format_string($heading);
+    }
+
+    /**
      * Set the course category this page belongs to manually. This automatically
      * sets $PAGE->course to be the site coures. You cannot use this method if
      * you have already set $PAGE->course - in that case, the category must be
@@ -598,6 +655,13 @@
         }
     }
 
+    /**
+     * @return boolean $cacheable can this page be cached by the user's browser.
+     */
+    public function set_cacheable($cacheable) {
+        $this->_cacheable = $cacheable;
+    }
+
 /// Initialisation methods =====================================================
 /// These set various things up in a default way.
 
Index: lib/upgradelib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/upgradelib.php,v
retrieving revision 1.21
diff -u -r1.21 upgradelib.php
--- lib/upgradelib.php	19 Jun 2009 14:25:56 -0000	1.21
+++ lib/upgradelib.php	25 Jun 2009 12:38:06 -0000
@@ -674,7 +674,7 @@
 
     $plugin = ($plugin==='moodle') ? null : $plugin;
 
-    $backtrace = print_backtrace($backtrace, true, true);
+    $backtrace = format_backtrace($backtrace, true);
 
     $version = null;
 
Index: lib/setuplib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/setuplib.php,v
retrieving revision 1.60
diff -u -r1.60 setuplib.php
--- lib/setuplib.php	24 Jun 2009 09:17:56 -0000	1.60
+++ lib/setuplib.php	25 Jun 2009 12:38:04 -0000
@@ -135,7 +135,7 @@
     $place = array('file'=>$ex->getFile(), 'line'=>$ex->getLine(), 'exception'=>get_class($ex));
     array_unshift($backtrace, $place);
 
-    $earlyerror = !isset($CFG->theme) || !isset($CFG->stylesheets);
+    $earlyerror = empty($OUTPUT);
     foreach ($backtrace as $stackframe) {
         if (isset($stackframe['function']) && $stackframe['function'] == 'print_header') {
             $earlyerror = true;
@@ -157,11 +157,190 @@
         $debuginfo = null;
     }
 
+    list($message, $moreinfourl, $link) = prepare_error_message($errorcode, $module, $link, $a);
+
     if ($earlyerror) {
-        _print_early_error($errorcode, $module, $a, $backtrace, $debuginfo);
+        // Error found before setup.php finished
+        _print_early_error($message, $backtrace, $debuginfo);
+    } else {
+        echo $OUTPUT->fatal_error($message, $moreinfourl, $link, debug_backtrace());
+    }
+
+    exit(1); // General error code
+}
+
+/**
+ * Abort execution, displaying an error message.
+ *
+ * @param string $errorcode The name of the language string containing the error message.
+ *      Normally this should be in the error.php lang file.
+ * @param string $module The language file to get the error message from.
+ * @param string $link The url where the user will be prompted to continue.
+ *      If no url is provided the user will be directed to the site index page.
+ * @param object $a Extra words and phrases that might be required in the error string
+ * @return void terminates script, does not return!
+ */
+function print_error($errorcode, $module = 'error', $link = '', $a = null) {
+    global $OUTPUT, $UNITTEST;
+
+    // Errors in unit test become exceptions, so you can unit test code that might call print_error().
+    if (!empty($UNITTEST->running)) {
+        throw new moodle_exception($errorcode, $module, $link, $a);
+    }
+
+    list($message, $moreinfourl, $link) = prepare_error_message($errorcode, $module, $link, $a);
+
+    if (empty($OUTPUT)) {
+        // Error found before setup.php finished
+        _print_early_error($message);
+    } else {
+        echo $OUTPUT->fatal_error($message, $moreinfourl, $link, debug_backtrace());
+    }
+
+    exit(1); // General error code
+}
+
+/**
+ * Private method used by print_error and default_exception_handler.
+ * @param $errorcode
+ * @param $module
+ * @param $link
+ * @param $a
+ * @return array
+ */
+function prepare_error_message($errorcode, $module, $link, $a) {
+    global $CFG, $DB, $SESSION;
+
+    if ($DB) {
+        // If you enable db debugging and exception is thrown, the print footer prints a lot of rubbish
+        $DB->set_debug(0);
+    }
+
+    if (empty($module) || $module == 'moodle' || $module == 'core') {
+        $module = 'error';
+    }
+    $message = get_string($errorcode, $module, $a);
+    if ($module === 'error' and strpos($message, '[[') === 0) {
+        // Search in moodle file if error specified - needed for backwards compatibility
+        $message = get_string($errorcode, 'moodle', $a);
+    }
+    $message = clean_text($message);
+
+    if (!empty($CFG->errordocroot)) {
+        $errordocroot = $CFG->errordocroot;
+    } else if (!empty($CFG->docroot)) {
+        $errordocroot = $CFG->docroot;
     } else {
-        _print_normal_error($errorcode, $module, $a, $link, $backtrace, $debuginfo);
+        $errordocroot = 'http://docs.moodle.org';
     }
+    if ($module === 'error') {
+        $modulelink = 'moodle';
+    } else {
+        $modulelink = $module;
+    }
+    $moreinfourl = $errordocroot . '/en/error/' . $modulelink . '/' . $errorcode;
+
+    if (empty($link) && !defined('ADMIN_EXT_HEADER_PRINTED')) {
+        if (!empty($SESSION->fromurl)) {
+            $link = $SESSION->fromurl;
+            unset($SESSION->fromurl);
+        } else {
+            $link = $CFG->wwwroot .'/';
+        }
+    }
+
+    return array($message, $moreinfourl, $link);
+}
+
+/**
+ * Internal function used by print_error. Do not use this directly!!
+ *
+ * Displays a fatal error before the theme is fully initialised.
+ * For example errors that occur during lib/setup.php.
+ *
+ * @param string $message
+ * @param string $link
+ * @param array $backtrace
+ * @param string $debuginfo
+ */
+function _print_early_error($message, $backtrace = null, $debuginfo = null) {
+    // In the name of protocol correctness, monitoring and performance
+    // profiling, set the appropriate error headers for machine comsumption
+    if (isset($_SERVER['SERVER_PROTOCOL'])) {
+        // Avoid it with cron.php. Note that we assume it's HTTP/1.x
+        @header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
+    }
+
+    // better disable any caching
+    @header('Content-Type: text/html; charset=utf-8');
+    @header('Cache-Control: no-store, no-cache, must-revalidate');
+    @header('Cache-Control: post-check=0, pre-check=0', false);
+    @header('Pragma: no-cache');
+    @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
+    @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
+
+    echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" ' . get_html_lang() . '>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>' . get_string('error') . '</title>
+</head><body>
+<div style="margin-top: 6em; margin-left:auto; margin-right:auto; color:#990000; text-align:center; font-size:large; border-width:1px;
+    border-color:black; background-color:#ffffee; border-style:solid; border-radius: 20px; border-collapse: collapse;
+    width: 80%; -moz-border-radius: 20px; padding: 15px">
+' . $message . '
+</div>';
+    if (debugging('', DEBUG_DEVELOPER)) {
+        if (!empty($debuginfo)) {
+            echo '<div class="notifytiny">' . $debuginfo . '</div>';
+        }
+        if (!empty($backtrace)) {
+            echo '<div class="notifytiny">Stack trace: ' . format_backtrace($backtrace, false) . '</div>';
+        }
+    }
+
+    echo '</body></html>';
+}
+
+/**
+ * Formats a backtrace ready for output.
+ *
+ * @param array $callers backtrace array, as returned by debug_backtrace().
+ * @param boolean $plaintext if false, generates HTML, if true generates plain text.
+ * @return string formatted backtrace, ready for output.
+ */
+function format_backtrace($callers, $plaintext = false) {
+    // do not use $CFG->dirroot because it might not be available in desctructors
+    $dirroot = dirname(dirname(__FILE__));
+ 
+    if (empty($callers)) {
+        return '';
+    }
+
+    $from = $plaintext ? '' : '<ul style="text-align: left">';
+    foreach ($callers as $caller) {
+        if (!isset($caller['line'])) {
+            $caller['line'] = '?'; // probably call_user_func()
+        }
+        if (!isset($caller['file'])) {
+            $caller['file'] = 'unknownfile'; // probably call_user_func()
+        }
+        $from .= $plaintext ? '* ' : '<li>';
+        $from .= 'line ' . $caller['line'] . ' of ' . str_replace($dirroot, '', $caller['file']);
+        if (isset($caller['function'])) {
+            $from .= ': call to ';
+            if (isset($caller['class'])) {
+                $from .= $caller['class'] . $caller['type'];
+            }
+            $from .= $caller['function'] . '()';
+        } else if (isset($caller['exception'])) {
+            $from .= ': '.$caller['exception'].' thrown';
+        }
+        $from .= $plaintext ? "\n" : '</li>';
+    }
+    $from .= $plaintext ? '' : '</ul>';
+
+    return $from;
 }
 
 /**
Index: lib/deprecatedlib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/deprecatedlib.php,v
retrieving revision 1.113
diff -u -r1.113 deprecatedlib.php
--- lib/deprecatedlib.php	23 Jun 2009 10:41:22 -0000	1.113
+++ lib/deprecatedlib.php	25 Jun 2009 12:38:03 -0000
@@ -202,6 +202,7 @@
  * parameters remain.  If possible, $align, $width and $color should not be defined at all.
  * Preferably just use print_box() in weblib.php
  *
+ * @deprecated
  * @param string $message The message to display
  * @param string $align alignment of the box, not the text (default center, left, right).
  * @param string $width width of the box, including units %, for example '100%'.
@@ -242,6 +243,7 @@
  * @return string|void Depending on $return
  */
 function print_simple_box_start($align='', $width='', $color='', $padding=5, $class='generalbox', $id='', $return=false) {
+    debugging('print_simple_box(_star/_end) is deprecated. Please use $OUTPUT->box(_star/_end) instead', DEBUG_DEVELOPER);
 
     $output = '';
 
@@ -1746,3 +1748,334 @@
     echo $OUTPUT->error_text($error);
 }
 
+/**
+ * Return the markup for the destination of the 'Skip to main content' links.
+ * Accessibility improvement for keyboard-only users.
+ *
+ * Used in course formats, /index.php and /course/index.php
+ *
+ * @deprecated use $OUTPUT->skip_link_target() in instead.
+ * @return string HTML element.
+ */
+function skip_main_destination() {
+    global $OUTPUT;
+    return $OUTPUT->skip_link_target();
+}
+
+/**
+ * Prints a string in a specified size  (retained for backward compatibility)
+ *
+ * @deprecated
+ * @param string $text The text to be displayed
+ * @param int $size The size to set the font for text display.
+ * @param bool $return If set to true output is returned rather than echoed Default false
+ * @return string|void String if return is true
+ */
+function print_headline($text, $size=2, $return=false) {
+    global $OUTPUT;
+    $output = $OUTPUT->heading($text, $size);
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Prints text in a format for use in headings.
+ *
+ * @deprecated
+ * @param string $text The text to be displayed
+ * @param string $deprecated No longer used. (Use to do alignment.)
+ * @param int $size The size to set the font for text display.
+ * @param string $class
+ * @param bool $return If set to true output is returned rather than echoed, default false
+ * @param string $id The id to use in the element
+ * @return string|void String if return=true nothing otherwise
+ */
+function print_heading($text, $deprecated = '', $size = 2, $class = 'main', $return = false, $id = '') {
+    global $OUTPUT;
+    if (!empty($deprecated)) {
+        debugging('Use of deprecated align attribute of print_heading. ' .
+                'Please do not specify styling in PHP code like that.', DEBUG_DEVELOPER);
+    }
+    $output = $OUTPUT->heading($text, $size, $class, $id);
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Output a standard heading block
+ *
+ * @deprecated
+ * @param string $heading The text to write into the heading
+ * @param string $class An additional Class Attr to use for the heading
+ * @param bool $return If set to true output is returned rather than echoed, default false
+ * @return string|void HTML String if return=true nothing otherwise
+ */
+function print_heading_block($heading, $class='', $return=false) {
+    global $OUTPUT;
+    $output = $OUTPUT->heading($heading, 2, 'headingblock header ' . moodle_renderer_base::prepare_classes($class));
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Print a message in a standard themed box.
+ * Replaces print_simple_box (see deprecatedlib.php)
+ *
+ * @deprecated
+ * @param string $message, the content of the box
+ * @param string $classes, space-separated class names.
+ * @param string $ids
+ * @param boolean $return, return as string or just print it
+ * @return string|void mixed string or void
+ */
+function print_box($message, $classes='generalbox', $ids='', $return=false) {
+    global $OUTPUT;
+    $output = $OUTPUT->box($message, $classes, $ids);
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Starts a box using divs
+ * Replaces print_simple_box_start (see deprecatedlib.php)
+ *
+ * @deprecated
+ * @param string $classes, space-separated class names.
+ * @param string $ids
+ * @param boolean $return, return as string or just print it
+ * @return string|void  string or void
+ */
+function print_box_start($classes='generalbox', $ids='', $return=false) {
+    global $OUTPUT;
+    $output = $OUTPUT->box_start($classes, $ids);
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Simple function to end a box (see above)
+ * Replaces print_simple_box_end (see deprecatedlib.php)
+ *
+ * @deprecated
+ * @param boolean $return, return as string or just print it
+ * @return string|void Depending on value of return
+ */
+function print_box_end($return=false) {
+    global $OUTPUT;
+    $output = $OUTPUT->box_end();
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Print a message in a standard themed container.
+ *
+ * @deprecated
+ * @param string $message, the content of the container
+ * @param boolean $clearfix clear both sides
+ * @param string $classes, space-separated class names.
+ * @param string $idbase
+ * @param boolean $return, return as string or just print it
+ * @return string|void Depending on value of $return
+ */
+function print_container($message, $clearfix=false, $classes='', $idbase='', $return=false) {
+    global $OUTPUT;
+    if ($clearfix) {
+        $classes .= ' clearfix';
+    }
+    $output = $OUTPUT->container($message, $classes, $idbase);
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Starts a container using divs
+ *
+ * @deprecated
+ * @param boolean $clearfix clear both sides
+ * @param string $classes, space-separated class names.
+ * @param string $idbase
+ * @param boolean $return, return as string or just print it
+ * @return string|void Based on value of $return
+ */
+function print_container_start($clearfix=false, $classes='', $idbase='', $return=false) {
+    global $OUTPUT;
+    if ($clearfix) {
+        $classes .= ' clearfix';
+    }
+    $output = $OUTPUT->container_start($classes, $idbase);
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Simple function to end a container (see above)
+ *
+ * @deprecated
+ * @param boolean $return, return as string or just print it
+ * @return string|void Based on $return
+ */
+function print_container_end($return=false) {
+    global $OUTPUT;
+    $output = $OUTPUT->container_end();
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Print a bold message in an optional color.
+ *
+ * @deprecated use $OUTPUT->notification instead.
+ * @param string $message The message to print out
+ * @param string $style Optional style to display message text in
+ * @param string $align Alignment option
+ * @param bool $return whether to return an output string or echo now
+ * @return string|bool Depending on $result 
+ */
+function notify($message, $classes = 'notifyproblem', $align = 'center', $return = false) {
+    global $OUTPUT;
+
+    if ($classes == 'green') {
+        debugging('Use of deprecated class name "green" in notify. Please change to "notifysuccess".', DEBUG_DEVELOPER);
+        $classes = 'notifysuccess'; // Backward compatible with old color system
+    }
+
+    $output = $OUTPUT->notification($message, $classes);
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Print a continue button that goes to a particular URL.
+ *
+ * @param string $link The url to create a link to.
+ * @param bool $return If set to true output is returned rather than echoed, default false
+ * @return string|void HTML String if return=true nothing otherwise
+ */
+function print_continue($link, $return = false) {
+    global $CFG, $OUTPUT;
+
+    if ($link == '') {
+        if (!empty($_SERVER['HTTP_REFERER'])) {
+            $link = $_SERVER['HTTP_REFERER'];
+            $link = str_replace('&', '&amp;', $link); // make it valid XHTML
+        } else {
+            $link = $CFG->wwwroot .'/';
+        }
+    }
+
+    $output = $OUTPUT->continue_button($link);
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+/**
+ * Returns a string containing a link to the user documentation for the current
+ * page. Also contains an icon by default. Shown to teachers and admin only.
+ *
+ * @global object
+ * @global object
+ * @param string $text The text to be displayed for the link
+ * @param string $iconpath The path to the icon to be displayed
+ * @return string The link to user documentation for this current page
+ */
+function page_doc_link($text='', $iconpath='') {
+    global $CFG, $PAGE;
+
+    if (empty($CFG->docroot) || during_initial_install()) {
+        return '';
+    }
+    if (!has_capability('moodle/site:doclinks', $PAGE->context)) {
+        return '';
+    }
+
+    $path = $PAGE->docspath;
+    if (!$path) {
+        return '';
+    }
+    return doc_link($path, $text, $iconpath);
+}
+
+/**
+ * Print a standard header
+ *
+ * @param string  $title Appears at the top of the window
+ * @param string  $heading Appears at the top of the page
+ * @param string  $navigation Array of $navlinks arrays (keys: name, link, type) for use as breadcrumbs links
+ * @param string  $focus Indicates form element to get cursor focus on load eg  inputform.password
+ * @param string  $meta Meta tags to be added to the header
+ * @param boolean $cache Should this page be cacheable?
+ * @param string  $button HTML code for a button (usually for module editing)
+ * @param string  $menu HTML code for a popup menu
+ * @param boolean $usexml use XML for this page
+ * @param string  $bodytags This text will be included verbatim in the <body> tag (useful for onload() etc)
+ * @param bool    $return If true, return the visible elements of the header instead of echoing them.
+ * @return string|void If return=true then string else void
+ */
+function print_header($title='', $heading='', $navigation='', $focus='',
+                      $meta='', $cache=true, $button='&nbsp;', $menu='',
+                      $usexml=false, $bodytags='', $return=false) {
+    global $PAGE, $OUTPUT;
+
+    $PAGE->set_title($title);
+    $PAGE->set_heading($heading);
+    // $navigation, $focus, $meta
+    $PAGE->set_cacheable($cache);
+    // $button, $menu
+    if ($usexml) {
+        throw new coding_exception('The $usexml parameter to print_header is no longer supported.');
+    }
+    // $bodytags
+
+    $output = $OUTPUT->header($PAGE, $navigation, $button, $menu);
+
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
+
+function print_footer($course = NULL, $usercourse = NULL, $return = false) {
+    global $PAGE, $OUTPUT;
+    // TODO check arguments.
+    $output = $OUTPUT->footer($PAGE);
+    if ($return) {
+        return $output;
+    } else {
+        echo $output;
+    }
+}
\ No newline at end of file
Index: lib/outputlib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/outputlib.php,v
retrieving revision 1.2
diff -u -r1.2 outputlib.php
--- lib/outputlib.php	23 Jun 2009 10:41:22 -0000	1.2
+++ lib/outputlib.php	25 Jun 2009 12:38:03 -0000
@@ -29,6 +29,20 @@
 
 
 /**
+ * Set up a preliminary $OUTPUT. This will be changed later once the correct theme
+ * for this page is known.
+ */
+function setup_bootstrat_output() {
+    global $OUTPUT;
+    if (CLI_SCRIPT) {
+        $OUTPUT = new cli_core_renderer(new xhtml_container_stack());
+    } else {
+        $OUTPUT = new moodle_core_renderer(new xhtml_container_stack());
+    }
+}
+
+
+/**
  * A renderer factory is just responsible for creating an appropriate renderer
  * for any given part of Moodle.
  *
@@ -87,6 +101,8 @@
     /** Used to cache renderers as they are created. */
     protected $renderers = array();
 
+    protected $containerstack;
+
     /**
      * Constructor.
      * @param object $theme the theme we are rendering for.
@@ -95,6 +111,7 @@
     public function __construct($theme, $page) {
         $this->theme = $theme;
         $this->page = $page;
+        $this->containerstack = new xhtml_container_stack();
     }
 
     /* Implement the interface method. */
@@ -164,10 +181,10 @@
     /* Implement the subclass method. */
     public function create_renderer($module) {
         if ($module == 'core') {
-            return new moodle_core_renderer($this->page->opencontainers);
+            return new moodle_core_renderer($this->containerstack);
         } else {
             $class = $this->standard_renderer_class_for_module($module);
-            return new $class($this->page->opencontainers, $this->get_renderer('core'));
+            return new $class($this->containerstack, $this->get_renderer('core'));
         }
     }
 }
@@ -191,7 +208,7 @@
      */
     public function __construct($theme, $page) {
         parent::__construct($theme, $page);
-        $this->renderers = array('core' => new custom_corners_core_renderer($this->page->opencontainers));
+        $this->renderers = array('core' => new custom_corners_core_renderer($this->containerstack));
     }
 }
 
@@ -245,9 +262,9 @@
             $classname = $prefix . $module . '_renderer';
             if (class_exists($classname)) {
                 if ($module == 'core') {
-                    return new $classname($this->page->opencontainers);
+                    return new $classname($this->containerstack);
                 } else {
-                    return new $classname($this->page->opencontainers, $this->get_renderer('core'));
+                    return new $classname($this->containerstack, $this->get_renderer('core'));
                 }
             }
         }
@@ -325,7 +342,7 @@
 
         // Create a template_renderer that copies the API of the standard renderer.
         $copiedclass = $this->standard_renderer_class_for_module($module);
-        return new template_renderer($copiedclass, $searchpaths, $this->page->opencontainers);
+        return new template_renderer($copiedclass, $searchpaths, $this->containerstack);
     }
 }
 
@@ -368,6 +385,7 @@
     }
 
     protected function output_attribute($name, $value) {
+        $value = trim($value);
         if ($value || is_numeric($value)) { // We want 0 to be output.
             return ' ' . $name . '="' . $value . '"';
         }
@@ -379,8 +397,11 @@
         }
         return $output;
     }
-    protected function output_class_attribute($classes) {
-        return $this->output_attribute('class', implode(' ', $classes));
+    public static function prepare_classes($classes) {
+        if (is_array($classes)) {
+            return implode(' ', array_unique($classes));
+        }
+        return $classes;
     }
 }
 
@@ -609,6 +630,14 @@
     }
 
     /**
+     * Return how many containers are currently open.
+     * @return integer how many containers are currently open.
+     */
+    public function nesting_depth() {
+        return count($this->opencontainsers);
+    }
+
+    /**
      * Close all but the last open container. This is useful in places like error
      * handling, where you want to close all the open containers (apart from <body>)
      * before outputting the error message.
@@ -658,6 +687,264 @@
  * @since     Moodle 2.0
  */
 class moodle_core_renderer extends moodle_renderer_base {
+    const PERFORMANCE_INFO_TOKEN = '%%PERFORMANCEINFO%%';
+    const END_HTML_TOKEN = '%%ENDHTML%%';
+
+    public function standard_head_html() {
+        global $CFG, $PAGE, $THEME;
+        $output = '';
+        $output .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . "\n";
+        $output .= '<meta name="keywords" content="moodle, ' . $title . '" />' . "\n";
+        // $output .= $PAGE->meta; TODO
+        if (!$PAGE->cacheable) {
+            $output .= '<meta http-equiv="pragma" content="no-cache" />' . "\n";
+            $output .= '<meta http-equiv="expires" content="0" />' . "\n";
+        }
+        ob_start();
+        include($CFG->javascript);
+        $output .= ob_get_contents();
+        ob_end_clean();
+        $output .= $PAGE->requires->get_head_code();
+
+        // Add the meta page from the themes if any were requested
+        // TODO kill this.
+        $metapage = '';
+        if (!isset($THEME->standardmetainclude) || $THEME->standardmetainclude) {
+            ob_start();
+            include_once($CFG->dirroot.'/theme/standard/meta.php');
+            $output .= ob_get_contents();
+            ob_end_clean();
+        }
+        if ($THEME->parent && (!isset($THEME->parentmetainclude) || $THEME->parentmetainclude)) {
+            if (file_exists($CFG->dirroot.'/theme/'.$THEME->parent.'/meta.php')) {
+                ob_start();
+                include_once($CFG->dirroot.'/theme/'.$THEME->parent.'/meta.php');
+                $output .= ob_get_contents();
+                ob_end_clean();
+            }
+        }
+        if (!isset($THEME->metainclude) || $THEME->metainclude) {
+            if (file_exists($CFG->dirroot.'/theme/'.current_theme().'/meta.php')) {
+                ob_start();
+                include_once($CFG->dirroot.'/theme/'.current_theme().'/meta.php');
+                $output .= ob_get_contents();
+                ob_end_clean();
+            }
+        }
+
+        return $output;
+    }
+
+    public function standard_top_of_body_html() {
+        global $PAGE;
+        echo $PAGE->requires->get_top_of_body_code();
+    }
+
+    public function standard_footer_html() {
+        echo self::PERFORMANCE_INFO_TOKEN;
+        if (debugging()) {
+            ?>
+            <div class="validators"><ul>
+              <li><a href="http://validator.w3.org/check?verbose=1&amp;ss=1&amp;uri=<?php echo urlencode(qualified_me()) ?>">Validate HTML</a></li>
+              <li><a href="http://www.contentquality.com/mynewtester/cynthia.exe?rptmode=-1&amp;url1=<?php echo urlencode(qualified_me()) ?>">Section 508 Check</a></li>
+              <li><a href="http://www.contentquality.com/mynewtester/cynthia.exe?rptmode=0&amp;warnp2n3e=1&amp;url1=<?php echo urlencode(qualified_me()) ?>">WCAG 1 (2,3) Check</a></li>
+            </ul></div>
+            <?php
+        }
+    }
+
+    public function standard_end_of_body_html() {
+        echo self::END_HTML_TOKEN;
+    }
+
+    public function home_link() {
+        global $CFG, $PAGE, $SITE;
+
+        if ($PAGE->pagetype == 'site-index') {
+            // Special case for site home page - please do not remove
+            return '<div class="sitelink">' .
+                   '<a title="Moodle ' . $CFG->release . '" href="http://moodle.org/">' .
+                   '<img style="width:100px;height:30px" src="' . $CFG->httpswwwroot . '/pix/moodlelogo.gif" alt="moodlelogo" /></a></div>';
+
+        } else if (!empty($CFG->target_release) && $CFG->target_release != $CFG->release) {
+            // Special case for during install/upgrade.
+            return '<div class="sitelink">'.
+                   '<a title="Moodle ' . $CFG->target_release . '" href="http://docs.moodle.org/en/Administrator_documentation" onclick="this.target=\'_blank\'">' .
+                   '<img style="width:100px;height:30px" src="' . $CFG->httpswwwroot . '/pix/moodlelogo.gif" alt="moodlelogo" /></a></div>';
+
+        } else if ($PAGE->course->id == $SITE->id) {
+            $homelink = '<div class="homelink"><a href="' . $CFG->wwwroot . '/">' .
+                    get_string('home') . '</a></div>';
+
+        } else {
+            return '<div class="homelink"><a href="' . $CFG->wwwroot . '/course/view.php?id=' . $PAGE->course->id . '">' .
+                    format_string($PAGE->course->shortname) . '</a></div>';
+        }
+    }
+
+    public function header($page = null, $navigation = '', $button='&nbsp;', $menu='') {
+        global $USER, $CFG, $THEME;
+
+        if (is_null($page)) {
+            global $PAGE;
+            $page = $PAGE;
+        }
+
+        if (gettype($navigation) == 'string' && strlen($navigation) != 0 && $navigation != 'home') {
+            debugging("print_header() was sent a string as 3rd ($navigation) parameter. "
+                    . "This is deprecated in favour of an array built by build_navigation(). Please upgrade your code.", DEBUG_DEVELOPER);
+        }
+
+        $page->set_state(moodle_page::STATE_PRINTING_HEADER);
+
+        $doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
+        $htmlattributes = get_html_lang(true);
+        $htmlattributes .= ' xmlns="http://www.w3.org/1999/xhtml"';  // See debug_header
+
+        // Add any stylesheets required using the horrible legacy mechanism. TODO kill this.
+        foreach ($CFG->stylesheets as $stylesheet) {
+            $page->requires->css($stylesheet, true);
+        }
+
+        // Set up some navigation variables
+        if (is_newnav($navigation) || $navigation != 'home') {
+            $home = false;
+        } else {
+            $home = true;
+            $navigation = '';
+        }
+
+        $navmenulist = isset($THEME->navmenulist) ? $THEME->navmenulist : '';
+
+        if ($button == '') {
+            $button = '&nbsp;';
+        }
+
+        // TODO
+        if (!empty($CFG->maintenance_enabled)) {
+            $button = '<a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=maintenancemode">'.get_string('maintenancemode', 'admin').'</a> '.$button;
+            if(!empty($title)) {
+                $title .= ' - ';
+            }
+            $title .= get_string('maintenancemode', 'admin');
+        }
+
+        if (!$menu and $navigation) {
+            $menu = user_login_string($page->course);
+        }
+
+        @header('Content-Type: text/html; charset=utf-8');
+        @header('Content-Script-Type: text/javascript');
+        @header('Content-Style-Type: text/css');
+
+        if ($page->cacheable) {
+            // Allow caching on "back" (but not on normal clicks)
+            @header('Cache-Control: private, pre-check=0, post-check=0, max-age=0');
+            @header('Pragma: no-cache');
+            @header('Expires: ');
+        } else {
+            // Do everything we can to always prevent clients and proxies caching
+            @header('Cache-Control: no-store, no-cache, must-revalidate');
+            @header('Cache-Control: post-check=0, pre-check=0', false);
+            @header('Pragma: no-cache');
+            @header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
+            @header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
+        }
+        @header('Accept-Ranges: none');
+    
+        message_popup_window();
+
+        $bodyattributes = ''; // $bodytags; // TODO
+
+        if (!isset($loggedinas)) {
+            $loggedinas = user_login_string($page->course, $USER);
+        }
+
+        if ($loggedinas == $menu) {
+            $menu = '';
+        }
+
+        // Find the appropriate page template, based on $page->generaltype.
+        $templatefile = $THEME->dir . '/layout.html';
+        if ($page->generaltype != 'normal') {
+            $specifictemplatefile = $THEME->dir . '/layout-' . $page->generaltype . '.html';
+            if (is_readable($specifictemplatefile)) {
+                $templatefile = $specifictemplatefile;
+            }
+        }
+
+        if (!is_readable($templatefile)) {
+            return $this->handle_legacy_theme();
+        }
+
+        // Render the template.
+        $template = $this->render_page_template($templatefile, $page, $loggedinas, $menu,
+                $button, $doctype, $htmlattributes, $bodyattributes, $navigation);
+
+        // Slice the template output into header and footer.
+        $cutpos = strpos($template, '[MAIN CONTENT GOES HERE]');
+        if ($cutpos === false) {
+            throw new coding_exception('Layout template ' . $templatefile . ' does not contain the string "[MAIN CONTENT GOES HERE]".');
+        }
+        $header = substr($template, 0, $cutpos);
+        $footer = substr($template, $cutpos + strlen('[MAIN CONTENT GOES HERE]'));
+
+        $header = force_strict_header($header); // TODO
+
+        $this->containerstack->push('header/footer', $footer);
+        $page->set_state(moodle_page::STATE_IN_BODY);
+        return $header . $this->skip_link_target();
+    }
+
+    protected function render_page_template($templatefile, $page, $loggedinas, $menu,
+            $button, $doctype, $htmlattributes, $bodyattributes, $navigation) {
+        global $USER, $CFG, $THEME;
+        // Set some pretend globals from the properties of this class.
+        $OUTPUT = $this;
+        $PAGE = $page;
+        $COURSE = $page->course;
+
+        ob_start();
+        include($templatefile);
+        $template = ob_get_contents();
+        ob_end_clean();
+        return $template;
+    }
+
+    public function footer($page = null) {
+        if (is_null($page)) {
+            global $PAGE;
+            $page = $PAGE;
+        }
+
+        $output = '';
+        if ($this->containerstack->nesting_depth() != 1) {
+            debugging('Some HTML tags were opened in the body of the page but not closed.', DEBUG_DEVELOPER);
+            $output .= $this->containerstack->pop_all_but_last();
+        }
+
+        $footer = $this->containerstack->pop('header/footer');
+
+        // Provide some performance info if required
+        $performanceinfo = '';
+        if (defined('MDL_PERF') || (!empty($CFG->perfdebug) and $CFG->perfdebug > 7)) {
+            $perf = get_performance_info();
+            if (defined('MDL_PERFTOLOG') && !function_exists('register_shutdown_function')) {
+                error_log("PERF: " . $perf['txt']);
+            }
+            if (defined('MDL_PERFTOFOOT') || debugging() || $CFG->perfdebug > 7) {
+                $performanceinfo = $perf['html'];
+            }
+        }
+        $footer = str_replace(self::PERFORMANCE_INFO_TOKEN, $performanceinfo, $footer);
+
+        $footer = str_replace(self::END_HTML_TOKEN, $page->requires->get_end_code(), $footer);
+
+        $page->set_state(moodle_page::STATE_DONE);
+
+        return $output . $footer;
+    }
+
     public function link_to_popup_window() {
         
     }
@@ -756,6 +1043,138 @@
         }
         return $this->output_tag('span', array('class' => 'error'), $message);
     }
+
+    /**
+     * Do not call this function directly.
+     *
+     * To terminate the current script with a fatal error, call the {@link print_error}
+     * function, or throw an exception. Doing either of those things will then call this
+     * funciton to display the error, before terminating the exection.
+     *
+     * @param string $message
+     * @param string $moreinfourl
+     * @param string $link
+     * @param array $backtrace
+     * @param string $debuginfo
+     * @param bool $showerrordebugwarning
+     * @return string the HTML to output.
+     */
+    public function fatal_error($message, $moreinfourl, $link, $backtrace,
+                $debuginfo = null, $showerrordebugwarning = false) {
+
+        $output = '';
+
+        if ($this->containerstack->nesting_depth() == 0) {
+            // Header not yet printed
+            @header('HTTP/1.0 404 Not Found');
+            print_header(get_string('error'));
+        } else {
+            $output .= $this->containerstack->pop_all_but_last();
+        }
+
+        $message = '<p class="errormessage">' . $message . '</p>'.
+                '<p class="errorcode"><a href="' . $moreinfourl . '">' .
+                get_string('moreinformation') . '</a></p>';
+        $output .= $this->box($message, 'errorbox');
+
+        if (debugging('', DEBUG_DEVELOPER)) {
+            if ($showerrordebugwarning) {
+                $output .= $this->notification('error() is a deprecated function. ' .
+                        'Please call print_error() instead of error()', 'notifytiny');
+            }
+            if (!empty($debuginfo)) {
+                $output .= $this->notification($debuginfo, 'notifytiny');
+            }
+            if (!empty($backtrace)) {
+                $output .= $this->notification('Stack trace: ' .
+                        format_backtrace($backtrace, true), 'notifytiny');
+            }
+        }
+
+        if (!empty($link)) {
+            $output .= $this->continue_button($link);
+        }
+
+        print_footer();
+
+        // Padding to encourage IE to display our error page, rather than its own.
+        $output .= str_repeat(' ', 512);
+
+        return $output;
+    }
+
+    /**
+     * Output a notification (that is, a status message about something that has
+     * just happened).
+     *
+     * @param string $message the message to print out
+     * @param string $classes normally 'notifyproblem' or 'notifysuccess'.
+     * @return string the HTML to output.
+     */
+    public function notification($message, $classes = 'notifyproblem') {
+        return $this->output_tag('div', array('class' =>
+                moodle_renderer_base::prepare_classes($classes)), clean_text($message));
+    }
+
+    /**
+     * Print a continue button that goes to a particular URL.
+     *
+     * @param string|moodle_url $link The url the button goes to.
+     * @return string the HTML to output.
+     */
+    public function continue_button($link) {
+        if (!is_a($link, 'moodle_url')) {
+            $link = new moodle_url($link);
+        }
+        return $this->output_tag('div', array('class' => 'continuebutton'),
+                print_single_button($link->out(true), $link->params(), get_string('continue'), 'get', '', true));
+    }
+
+    /**
+     * Output the place a skip link goes to.
+     * @param $id The target name from the corresponding $PAGE->requires->skip_link_to($target) call.
+     * @return string the HTML to output.
+     */
+    public function skip_link_target($id = 'maincontent') {
+        return $this->output_tag('span', array('id' => $id), '');
+    }
+
+    public function heading($text, $level, $classes = 'main', $id = '') {
+        $level = (integer) $level;
+        if ($level < 1 or $level > 6) {
+            throw new coding_exception('Heading level must be an integer between 1 and 6.');
+        }
+        return $this->output_tag('h' . $level,
+                array('id' => $id, 'class' => moodle_renderer_base::prepare_classes($classes)), $text);
+    }
+
+    public function box($contents, $classes = 'generalbox', $id = '') {
+        return $this->box_start($classes, $id) . $contents . $this->box_end();
+    }
+
+    public function box_start($classes = 'generalbox', $id = '') {
+        $this->containerstack->push('box', $this->output_end_tag('div'));
+        return $this->output_start_tag('div', array('id' => $id,
+                'class' => 'box ' . moodle_renderer_base::prepare_classes($classes)));
+    }
+
+    public function box_end() {
+        return $this->containerstack->pop('box');
+    }
+
+    public function container($contents, $classes = '', $id = '') {
+        return $this->container_start($classes, $id) . $contents . $this->container_end();
+    }
+
+    public function container_start($classes = '', $id = '') {
+        $this->containerstack->push('container', $this->output_end_tag('div'));
+        return $this->output_start_tag('div', array('id' => $id,
+                'class' => moodle_renderer_base::prepare_classes($classes)));
+    }
+
+    public function container_end() {
+        return $this->containerstack->pop('container');
+    }
 }
 
 
@@ -838,7 +1257,7 @@
 
 /**
  * This class hold all the information required to describe a <select> menu that
- * will be printed by {@link moodle_core_renderer::select_menu()}. (Or by an overrides
+ * will be printed by {@link moodle_core_renderer::select_menu()}. (Or by an overridden
  * version of that method in a subclass.)
  *
  * All the fields that are not set by the constructor have sensible defaults, so
@@ -945,6 +1364,61 @@
 
 
 /**
+ * A renderer that generates output for commandlines scripts.
+ *
+ * The implementation of this renderer is probably incomplete.
+ *
+ * @copyright 2009 Tim Hunt
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 2.0
+ */
+class cli_core_renderer extends moodle_core_renderer {
+    public function header($page = null) {
+        if (is_null($page)) {
+            global $PAGE;
+            $page = $PAGE;
+        }
+
+        return $PAGE->$heading . "\n";
+    }
+
+    public function heading($text, $level, $classes = 'main', $id = '') {
+        $text .= "\n";
+        switch ($level) {
+            case 1:
+                return '=>' . $text;
+            case 2:
+                return '-->' . $text;
+            default:
+                return $text;
+        }
+    }
+
+    public function fatal_error($errorcode, $module, $a, $link, $backtrace,
+                $debuginfo = null, $showerrordebugwarning = false) {
+        $output = "!!! $message !!!\n";
+
+        if (debugging('', DEBUG_DEVELOPER)) {
+            if (!empty($debuginfo)) {
+                $this->notification($debuginfo, 'notifytiny');
+            }
+            if (!empty($backtrace)) {
+                $this->notification('Stack trace: ' . format_backtrace($backtrace, true), 'notifytiny');
+            }
+        }
+    }
+
+    public function notification($message, $classes = 'notifyproblem') {
+        $message = clean_text($message);
+        if ($style === 'notifysuccess') {
+            return "++ $message ++\n";
+        }
+        return "!! $message !!\n";
+    }
+}
+
+
+/**
  * A renderer for the custom corner theme, and other themes based on it.
  *
  * Generates the slightly different HTML that the custom corners theme wants.
@@ -954,7 +1428,59 @@
  * @since     Moodle 2.0
  */
 class custom_corners_core_renderer extends moodle_core_renderer {
+    protected function custom_corners_divs($classes = '', $idbase = '') {
+        if (strpos($classes, 'clearfix') !== false) {
+            $clearfix = ' clearfix';
+            $classes = trim(str_replace('clearfix', '', $classes));
+        } else {
+            $clearfix = '';
+        }
 
-    // TODO
-}
+        // Analise if we want ids for the custom corner elements
+        $id = '';
+        $idbt = '';
+        $idi1 = '';
+        $idi2 = '';
+        $idi3 = '';
+        $idbb = '';
+        if ($idbase) {
+            $id = $idbase;
+            $idbt = $idbase . '-bt';
+            $idi1 = $idbase . '-i1';
+            $idi2 = $idbase . '-i2';
+            $idi3 = $idbase . '-i3';
+            $idbb = $idbase . '-bb';
+        }
+
+        // Calculate current level
+        $level = $this->containerstack->nesting_depth();
+
+        // Create start tags.
+        $start = $this->output_start_tag('div', array('id' => $idbb, 'class' => "wrap wraplevel$level $classes")) . "\n";
+        $start .= $this->output_tag('div', array('id' => $idbt, 'class' => 'bt'), '<div>&nbsp;</div>') . "\n";
+        $start .= $this->output_start_tag('div', array('id' => $idi1, 'class' => 'i1'));
+        $start .= $this->output_start_tag('div', array('id' => $idi2, 'class' => 'i2'));
+        $start .= $this->output_start_tag('div', array('id' => $idi3, 'class' => "i3$clearfix"));
+
+        // Create end tags.
+        $end = $this->output_end_tag('div');
+        $end .= $this->output_end_tag('div');
+        $end .= $this->output_end_tag('div');
+        $end .= $this->output_tag('div', array('id' => $idbb, 'class' => 'bb'), '<div>&nbsp;</div>') . "\n";
+        $end .= $this->output_end_tag('div');
+
+        return array($start, $end);
+    }
+
+    public function box_start($classes = 'generalbox', $id = '') {
+        list($start, $end) = $this->custom_corners_divs('ccbox box ' . moodle_renderer_base::prepare_classes($classes), $id);
+        $this->containerstack->push('box', $end);
+        return $start;
+    }
 
+    public function container_start($classes = '', $id = '') {
+        list($start, $end) = $this->custom_corners_divs(moodle_renderer_base::prepare_classes($classes), $id);
+        $this->containerstack->push('container', $end);
+        return $start;
+    }
+}
Index: lib/setup.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/setup.php,v
retrieving revision 1.275
diff -u -r1.275 setup.php
--- lib/setup.php	19 Jun 2009 14:25:56 -0000	1.275
+++ lib/setup.php	25 Jun 2009 12:38:04 -0000
@@ -94,11 +94,19 @@
 global $COURSE;
 
 /**
- * $THEME is a global that defines the site theme.
+ * $OUTPUT is an instance of moodle_core_renderer or one of its subclasses. Use
+ * it to generate HTML for output.
  *
- * Items found in the theme record:
- *  - $THEME->cellheading - Cell colors.
- *  - $THEME->cellheading2 - Alternate cell colors.
+ * $OUTPUT is initialised when the theme is setup. That normally happens during
+ * the call to require_login, or $PAGE->set_course.
+ *
+ * @global object $OUTPUT
+ * @name $OUTPUT
+ */
+global $OUTPUT;
+
+/**
+ * $THEME is a global that defines the current theme.
  *
  * @global object $THEME
  * @name THEME
@@ -222,7 +230,8 @@
     require_once($CFG->libdir .'/textlib.class.php');   // Functions to handle multibyte strings
     require_once($CFG->libdir .'/filterlib.php');       // Functions for filtering test as it is output
     require_once($CFG->libdir .'/ajax/ajaxlib.php');    // Functions for managing our use of JavaScript and YUI
-    require_once($CFG->libdir .'/weblib.php');          // Functions for producing HTML
+    require_once($CFG->libdir .'/weblib.php');          // Functions relating to HTTP and content
+    require_once($CFG->libdir .'/outputlib.php');       // Functions for generating output
     require_once($CFG->libdir .'/dmllib.php');          // Database access
     require_once($CFG->libdir .'/datalib.php');         // Legacy lib with a big-mix of functions.
     require_once($CFG->libdir .'/accesslib.php');       // Access control functions
@@ -246,6 +255,9 @@
 /// make sure PHP is not severly misconfigured
     setup_validate_php_configuration();
 
+/// Create an initial $OUTPUT. This will be changes later once we know the theme.
+    setup_bootstrat_output();
+
 /// Connect to the database
     setup_DB();
 
Index: lib/dml/moodle_database.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/dml/moodle_database.php,v
retrieving revision 1.95
diff -u -r1.95 moodle_database.php
--- lib/dml/moodle_database.php	13 Jun 2009 15:59:55 -0000	1.95
+++ lib/dml/moodle_database.php	25 Jun 2009 12:38:09 -0000
@@ -400,7 +400,7 @@
                 $log->sqlparams  = var_export((array)$this->last_params, true);
                 $log->error      = (int)$iserror;
                 $log->info       = $iserror ? $error : null;
-                $log->backtrace  = print_backtrace($backtrace, true, true);
+                $log->backtrace  = format_backtrace($backtrace, true);
                 $log->exectime   = $time;
                 $log->timelogged = time();
                 $this->insert_record('log_queries', $log);
Index: lib/simpletest/testpagelib_moodlepage.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/simpletest/testpagelib_moodlepage.php,v
retrieving revision 1.17
diff -u -r1.17 testpagelib_moodlepage.php
--- lib/simpletest/testpagelib_moodlepage.php	22 Jun 2009 06:30:21 -0000	1.17
+++ lib/simpletest/testpagelib_moodlepage.php	25 Jun 2009 12:38:09 -0000
@@ -324,6 +324,32 @@
         // Validate
         $this->assertEqual('somestring', $this->testpage->subpage);
     }
+
+    public function test_set_heading() {
+        // Exercise SUT
+        $this->testpage->set_heading('a heading');
+        // Validate
+        $this->assertEqual('a heading', $this->testpage->heading);
+    }
+
+    public function test_set_title() {
+        // Exercise SUT
+        $this->testpage->set_title('a title');
+        // Validate
+        $this->assertEqual('a title', $this->testpage->title);
+    }
+
+    public function test_default_generaltype() {
+        // Exercise SUT and Validate
+        $this->assertEqual('normal', $this->testpage->generaltype);
+    }
+
+    public function test_set_generaltype() {
+        // Exercise SUT
+        $this->testpage->set_generaltype('type');
+        // Validate
+        $this->assertEqual('type', $this->testpage->generaltype);
+    }
 }
 
 /**
Index: lib/simpletest/testoutputlib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/simpletest/testoutputlib.php,v
retrieving revision 1.2
diff -u -r1.2 testoutputlib.php
--- lib/simpletest/testoutputlib.php	23 Jun 2009 10:41:22 -0000	1.2
+++ lib/simpletest/testoutputlib.php	25 Jun 2009 12:38:09 -0000
@@ -155,9 +155,7 @@
 
     public function setUp() {
         parent::setUp();
-        $page = new stdClass;
-        $page->opencontainers = new xhtml_container_stack();
-        $this->factory = new standard_renderer_factory(null, $page);
+        $this->factory = new standard_renderer_factory(null, null);
     }
 
     public function tearDown() {
@@ -188,9 +186,7 @@
 
     public function setUp() {
         parent::setUp();
-        $page = new stdClass;
-        $page->opencontainers = new xhtml_container_stack();
-        $this->factory = new custom_corners_renderer_factory(null, $page);
+        $this->factory = new custom_corners_renderer_factory(null, null);
     }
 
     public function tearDown() {
@@ -246,7 +242,6 @@
         $this->foldertocleanup = $CFG->themedir;
 
         $this->page = new stdClass;
-        $this->page->opencontainers = new xhtml_container_stack();
     }
 
     public function tearDown() {
@@ -414,7 +409,6 @@
         $this->foldertocleanup = $CFG->themedir;
 
         $this->page = new stdClass;
-        $this->page->opencontainers = new xhtml_container_stack();
     }
 
     public function tearDown() {
Index: index.php
===================================================================
RCS file: /cvsroot/moodle/moodle/index.php,v
retrieving revision 1.233
diff -u -r1.233 index.php
--- index.php	31 May 2009 14:42:31 -0000	1.233
+++ index.php	25 Jun 2009 12:38:02 -0000
@@ -96,6 +96,7 @@
     $PAGE->set_other_editing_capability('moodle/course:manageactivities');
     $PAGE->set_url('');
     $PAGE->set_docs_path('');
+    $PAGE->set_generaltype('home');
     $pageblocks = blocks_setup($PAGE);
     $editing = $PAGE->user_is_editing();
     $preferred_width_left  = bounded_number(BLOCK_L_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
Index: admin/report/unittest/test_tables.php
===================================================================
RCS file: /cvsroot/moodle/moodle/admin/report/unittest/test_tables.php,v
retrieving revision 1.4
diff -u -r1.4 test_tables.php
--- admin/report/unittest/test_tables.php	19 Jun 2009 14:26:02 -0000	1.4
+++ admin/report/unittest/test_tables.php	25 Jun 2009 12:38:02 -0000
@@ -35,7 +35,6 @@
     $CFG->config_php_settings = $real_cfg->config_php_settings;
     $CFG->frametarget         = $real_cfg->frametarget;
     $CFG->framename           = $real_cfg->framename;
-    $CFG->footer              = $real_cfg->footer;
     $CFG->debug               = 0;
 
     $DB = moodle_database::get_driver_instance($CFG->dbtype, $CFG->dblibrary);
Index: theme/standard/layout.html
===================================================================
RCS file: theme/standard/layout.html
diff -N theme/standard/layout.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ theme/standard/layout.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,49 @@
+<?php echo $doctype ?>
+<html <?php echo $htmlattributes ?>>
+<head>
+    <title><?php echo $PAGE->title ?></title>
+    <link rel="shortcut icon" href="<?php echo $CFG->themewww .'/'. current_theme() ?>/favicon.ico" />
+    <?php echo $OUTPUT->standard_head_html() ?>
+</head>
+<body id="<?php echo $PAGE->pagetype ?>" class="<?php echo $PAGE->bodyclasses ?>"<?php echo $bodyattributes ?>>
+<?php echo $OUTPUT->standard_top_of_body_html() ?>
+
+<div id="page">
+
+<?php if ($PAGE->heading) { ?>
+    <div id="header" class="clearfix">
+        <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
+        <div class="headermenu"><?php echo $menu ?></div>
+    </div>
+<?php } ?>
+
+<?php if ($navigation) { // This is the navigation bar with breadcrumbs  ?>
+    <div class="navbar clearfix">
+        <div class="breadcrumb"><?php print_navigation($navigation); ?></div>
+        <div class="navbutton"><?php echo $button; ?></div>
+    </div>
+<?php } else if ($PAGE->heading) { // If no navigation, but a heading, then print a line ?>
+    <hr />
+<?php } ?>
+<!-- END OF HEADER -->
+
+    <div id="content" class="clearfix">
+        [MAIN CONTENT GOES HERE]
+    </div>
+
+<!-- START OF FOOTER -->
+    <div id="footer" class="clearfix">
+        <p class="helplink">
+        <?php echo page_doc_link(get_string('moodledocslink')) ?>
+        </p>
+
+        <?php
+        echo $loggedinas;
+        echo $OUTPUT->home_link();
+        echo $OUTPUT->standard_footer_html();
+        ?>
+    </div>
+</div>
+<?php echo $OUTPUT->standard_end_of_body_html() ?>
+</body>
+</html>
Index: theme/standard/layout-home.html
===================================================================
RCS file: theme/standard/layout-home.html
diff -N theme/standard/layout-home.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ theme/standard/layout-home.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,47 @@
+<?php echo $doctype ?>
+<html <?php echo $htmlattributes ?>>
+<head>
+    <title><?php echo $PAGE->title ?></title>
+    <link rel="shortcut icon" href="<?php echo $CFG->themewww .'/'. current_theme() ?>/favicon.ico" />
+    <?php echo $OUTPUT->standard_head_html() ?>
+</head>
+<body id="<?php echo $PAGE->pagetype ?>" class="<?php echo $PAGE->bodyclasses ?>"<?php echo $bodyattributes ?>>
+<?php echo $OUTPUT->standard_top_of_body_html() ?>
+
+<div id="page">
+
+    <div id="header-home" class="clearfix">
+        <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
+        <div class="headermenu"><?php echo $menu ?></div>
+    </div>
+
+<?php if ($navigation) { // This is the navigation bar with breadcrumbs  ?>
+    <div class="navbar clearfix">
+        <div class="breadcrumb"><?php print_navigation($navigation); ?></div>
+        <div class="navbutton"><?php echo $button; ?></div>
+    </div>
+<?php } else if ($PAGE->heading) { // If no navigation, but a heading, then print a line ?>
+    <hr />
+<?php } ?>
+<!-- END OF HEADER -->
+
+    <div id="content" class="clearfix">
+        [MAIN CONTENT GOES HERE]
+    </div>
+
+<!-- START OF FOOTER -->
+    <div id="footer" class="clearfix">
+        <p class="helplink">
+        <?php echo page_doc_link(get_string('moodledocslink')) ?>
+        </p>
+
+        <?php
+        echo $loggedinas;
+        echo $OUTPUT->home_link();
+        echo $OUTPUT->standard_footer_html();
+        ?>
+    </div>
+</div>
+<?php echo $OUTPUT->standard_end_of_body_html() ?>
+</body>
+</html>
Index: theme/standardwhite/layout-home.html
===================================================================
RCS file: theme/standardwhite/layout-home.html
diff -N theme/standardwhite/layout-home.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ theme/standardwhite/layout-home.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,47 @@
+<?php echo $doctype ?>
+<html <?php echo $htmlattributes ?>>
+<head>
+    <title><?php echo $PAGE->title ?></title>
+    <link rel="shortcut icon" href="<?php echo $CFG->themewww .'/'. current_theme() ?>/favicon.ico" />
+    <?php echo $OUTPUT->standard_head_html() ?>
+</head>
+<body id="<?php echo $PAGE->pagetype ?>" class="<?php echo $PAGE->bodyclasses ?>"<?php echo $bodyattributes ?>>
+<?php echo $OUTPUT->standard_top_of_body_html() ?>
+
+<div id="page">
+
+    <div id="header-home" class="clearfix">
+        <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
+        <div class="headermenu"><?php echo $menu ?></div>
+    </div>
+
+<?php if ($navigation) { // This is the navigation bar with breadcrumbs  ?>
+    <div class="navbar clearfix">
+        <div class="breadcrumb"><?php print_navigation($navigation); ?></div>
+        <div class="navbutton"><?php echo $button; ?></div>
+    </div>
+<?php } else if ($PAGE->heading) { // If no navigation, but a heading, then print a line ?>
+    <hr />
+<?php } ?>
+<!-- END OF HEADER -->
+
+    <div id="content" class="clearfix">
+        [MAIN CONTENT GOES HERE]
+    </div>
+
+<!-- START OF FOOTER -->
+    <div id="footer" class="clearfix">
+        <p class="helplink">
+        <?php echo page_doc_link(get_string('moodledocslink')) ?>
+        </p>
+
+        <?php
+        echo $loggedinas;
+        echo $OUTPUT->home_link();
+        echo $OUTPUT->standard_footer_html();
+        ?>
+    </div>
+</div>
+<?php echo $OUTPUT->standard_end_of_body_html() ?>
+</body>
+</html>
Index: theme/standardwhite/layout.html
===================================================================
RCS file: theme/standardwhite/layout.html
diff -N theme/standardwhite/layout.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ theme/standardwhite/layout.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,49 @@
+<?php echo $doctype ?>
+<html <?php echo $htmlattributes ?>>
+<head>
+    <title><?php echo $PAGE->title ?></title>
+    <link rel="shortcut icon" href="<?php echo $CFG->themewww .'/'. current_theme() ?>/favicon.ico" />
+    <?php echo $OUTPUT->standard_head_html() ?>
+</head>
+<body id="<?php echo $PAGE->pagetype ?>" class="<?php echo $PAGE->bodyclasses ?>"<?php echo $bodyattributes ?>>
+<?php echo $OUTPUT->standard_top_of_body_html() ?>
+
+<div id="page">
+
+<?php if ($PAGE->heading) { ?>
+    <div id="header" class="clearfix">
+        <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
+        <div class="headermenu"><?php echo $menu ?></div>
+    </div>
+<?php } ?>
+
+<?php if ($navigation) { // This is the navigation bar with breadcrumbs  ?>
+    <div class="navbar clearfix">
+        <div class="breadcrumb"><?php print_navigation($navigation); ?></div>
+        <div class="navbutton"><?php echo $button; ?></div>
+    </div>
+<?php } else if ($PAGE->heading) { // If no navigation, but a heading, then print a line ?>
+    <hr />
+<?php } ?>
+<!-- END OF HEADER -->
+
+    <div id="content" class="clearfix">
+        [MAIN CONTENT GOES HERE]
+    </div>
+
+<!-- START OF FOOTER -->
+    <div id="footer" class="clearfix">
+        <p class="helplink">
+        <?php echo page_doc_link(get_string('moodledocslink')) ?>
+        </p>
+
+        <?php
+        echo $loggedinas;
+        echo $OUTPUT->home_link();
+        echo $OUTPUT->standard_footer_html();
+        ?>
+    </div>
+</div>
+<?php echo $OUTPUT->standard_end_of_body_html() ?>
+</body>
+</html>
