]> git.openstreetmap.org Git - chef.git/blobdiff - cookbooks/dmca/files/default/html/HTML/QuickForm.php
Configure the dmca form site on ridley
[chef.git] / cookbooks / dmca / files / default / html / HTML / QuickForm.php
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm.php b/cookbooks/dmca/files/default/html/HTML/QuickForm.php
new file mode 100644 (file)
index 0000000..f769b1f
--- /dev/null
@@ -0,0 +1,2073 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Create, validate and process HTML forms
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: This source file is subject to version 3.01 of the PHP license
+ * that is available through the world-wide-web at the following URI:
+ * http://www.php.net/license/3_01.txt If you did not receive a copy of
+ * the PHP License and are unable to obtain it through the web, please
+ * send a note to license@php.net so we can mail you a copy immediately.
+ *
+ * @category    HTML
+ * @package     HTML_QuickForm
+ * @author      Adam Daniel <adaniel1@eesus.jnj.com>
+ * @author      Bertrand Mansion <bmansion@mamasam.com>
+ * @author      Alexey Borzov <avb@php.net>
+ * @copyright   2001-2011 The PHP Group
+ * @license     http://www.php.net/license/3_01.txt PHP License 3.01
+ * @version     CVS: $Id$
+ * @link        http://pear.php.net/package/HTML_QuickForm
+ */
+
+/**
+ * PEAR and PEAR_Error classes, for error handling
+ */
+require_once 'PEAR.php';
+/**
+ * Base class for all HTML classes
+ */
+require_once 'HTML/Common.php';
+/**
+ * Static utility methods
+ */
+require_once 'HTML/QuickForm/utils.php';
+
+/**
+ * Element types known to HTML_QuickForm
+ * @see HTML_QuickForm::registerElementType(), HTML_QuickForm::getRegisteredTypes(),
+ *      HTML_QuickForm::isTypeRegistered()
+ * @global array $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']
+ */
+$GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'] =
+        array(
+            'group'         =>array('HTML/QuickForm/group.php','HTML_QuickForm_group'),
+            'hidden'        =>array('HTML/QuickForm/hidden.php','HTML_QuickForm_hidden'),
+            'reset'         =>array('HTML/QuickForm/reset.php','HTML_QuickForm_reset'),
+            'checkbox'      =>array('HTML/QuickForm/checkbox.php','HTML_QuickForm_checkbox'),
+            'file'          =>array('HTML/QuickForm/file.php','HTML_QuickForm_file'),
+            'image'         =>array('HTML/QuickForm/image.php','HTML_QuickForm_image'),
+            'password'      =>array('HTML/QuickForm/password.php','HTML_QuickForm_password'),
+            'radio'         =>array('HTML/QuickForm/radio.php','HTML_QuickForm_radio'),
+            'button'        =>array('HTML/QuickForm/button.php','HTML_QuickForm_button'),
+            'submit'        =>array('HTML/QuickForm/submit.php','HTML_QuickForm_submit'),
+            'select'        =>array('HTML/QuickForm/select.php','HTML_QuickForm_select'),
+            'hiddenselect'  =>array('HTML/QuickForm/hiddenselect.php','HTML_QuickForm_hiddenselect'),
+            'text'          =>array('HTML/QuickForm/text.php','HTML_QuickForm_text'),
+            'textarea'      =>array('HTML/QuickForm/textarea.php','HTML_QuickForm_textarea'),
+            'link'          =>array('HTML/QuickForm/link.php','HTML_QuickForm_link'),
+            'advcheckbox'   =>array('HTML/QuickForm/advcheckbox.php','HTML_QuickForm_advcheckbox'),
+            'date'          =>array('HTML/QuickForm/date.php','HTML_QuickForm_date'),
+            'static'        =>array('HTML/QuickForm/static.php','HTML_QuickForm_static'),
+            'header'        =>array('HTML/QuickForm/header.php', 'HTML_QuickForm_header'),
+            'html'          =>array('HTML/QuickForm/html.php', 'HTML_QuickForm_html'),
+            'hierselect'    =>array('HTML/QuickForm/hierselect.php', 'HTML_QuickForm_hierselect'),
+            'autocomplete'  =>array('HTML/QuickForm/autocomplete.php', 'HTML_QuickForm_autocomplete'),
+            'xbutton'       =>array('HTML/QuickForm/xbutton.php','HTML_QuickForm_xbutton')
+        );
+
+/**
+ * Validation rules known to HTML_QuickForm
+ * @see HTML_QuickForm::registerRule(), HTML_QuickForm::getRegisteredRules(),
+ *      HTML_QuickForm::isRuleRegistered()
+ * @global array $GLOBALS['_HTML_QuickForm_registered_rules']
+ */
+$GLOBALS['_HTML_QuickForm_registered_rules'] = array(
+    'required'      => array('html_quickform_rule_required', 'HTML/QuickForm/Rule/Required.php'),
+    'maxlength'     => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
+    'minlength'     => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
+    'rangelength'   => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
+    'email'         => array('html_quickform_rule_email',    'HTML/QuickForm/Rule/Email.php'),
+    'regex'         => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
+    'lettersonly'   => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
+    'alphanumeric'  => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
+    'numeric'       => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
+    'nopunctuation' => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
+    'nonzero'       => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
+    'callback'      => array('html_quickform_rule_callback', 'HTML/QuickForm/Rule/Callback.php'),
+    'compare'       => array('html_quickform_rule_compare',  'HTML/QuickForm/Rule/Compare.php')
+);
+
+// {{{ error codes
+
+/**#@+
+ * Error codes for HTML_QuickForm
+ *
+ * Codes are mapped to textual messages by errorMessage() method, if you add a
+ * new code be sure to add a new message for it to errorMessage()
+ *
+ * @see HTML_QuickForm::errorMessage()
+ */
+define('QUICKFORM_OK',                      1);
+define('QUICKFORM_ERROR',                  -1);
+define('QUICKFORM_INVALID_RULE',           -2);
+define('QUICKFORM_NONEXIST_ELEMENT',       -3);
+define('QUICKFORM_INVALID_FILTER',         -4);
+define('QUICKFORM_UNREGISTERED_ELEMENT',   -5);
+define('QUICKFORM_INVALID_ELEMENT_NAME',   -6);
+define('QUICKFORM_INVALID_PROCESS',        -7);
+define('QUICKFORM_DEPRECATED',             -8);
+define('QUICKFORM_INVALID_DATASOURCE',     -9);
+/**#@-*/
+
+// }}}
+
+/**
+ * Create, validate and process HTML forms
+ *
+ * @category    HTML
+ * @package     HTML_QuickForm
+ * @author      Adam Daniel <adaniel1@eesus.jnj.com>
+ * @author      Bertrand Mansion <bmansion@mamasam.com>
+ * @author      Alexey Borzov <avb@php.net>
+ * @version     Release: 3.2.16
+ */
+class HTML_QuickForm extends HTML_Common
+{
+    // {{{ properties
+
+    /**
+     * Array containing the form fields
+     * @since     1.0
+     * @var  array
+     * @access   private
+     */
+    var $_elements = array();
+
+    /**
+     * Array containing element name to index map
+     * @since     1.1
+     * @var  array
+     * @access   private
+     */
+    var $_elementIndex = array();
+
+    /**
+     * Array containing indexes of duplicate elements
+     * @since     2.10
+     * @var  array
+     * @access   private
+     */
+    var $_duplicateIndex = array();
+
+    /**
+     * Array containing required field IDs
+     * @since     1.0
+     * @var  array
+     * @access   private
+     */
+    var $_required = array();
+
+    /**
+     * Prefix message in javascript alert if error
+     * @since     1.0
+     * @var  string
+     * @access   public
+     */
+    var $_jsPrefix = 'Invalid information entered.';
+
+    /**
+     * Postfix message in javascript alert if error
+     * @since     1.0
+     * @var  string
+     * @access   public
+     */
+    var $_jsPostfix = 'Please correct these fields.';
+
+    /**
+     * Datasource object implementing the informal
+     * datasource protocol
+     * @since     3.3
+     * @var  object
+     * @access   private
+     */
+    var $_datasource;
+
+    /**
+     * Array of default form values
+     * @since     2.0
+     * @var  array
+     * @access   private
+     */
+    var $_defaultValues = array();
+
+    /**
+     * Array of constant form values
+     * @since     2.0
+     * @var  array
+     * @access   private
+     */
+    var $_constantValues = array();
+
+    /**
+     * Array of submitted form values
+     * @since     1.0
+     * @var  array
+     * @access   private
+     */
+    var $_submitValues = array();
+
+    /**
+     * Array of submitted form files
+     * @since     1.0
+     * @var  integer
+     * @access   public
+     */
+    var $_submitFiles = array();
+
+    /**
+     * Value for maxfilesize hidden element if form contains file input
+     * @since     1.0
+     * @var  integer
+     * @access   public
+     */
+    var $_maxFileSize = 1048576; // 1 Mb = 1048576
+
+    /**
+     * Flag to know if all fields are frozen
+     * @since     1.0
+     * @var  boolean
+     * @access   private
+     */
+    var $_freezeAll = false;
+
+    /**
+     * Array containing the form rules
+     * @since     1.0
+     * @var  array
+     * @access   private
+     */
+    var $_rules = array();
+
+    /**
+     * Form rules, global variety
+     * @var     array
+     * @access  private
+     */
+    var $_formRules = array();
+
+    /**
+     * Array containing the validation errors
+     * @since     1.0
+     * @var  array
+     * @access   private
+     */
+    var $_errors = array();
+
+    /**
+     * Note for required fields in the form
+     * @var       string
+     * @since     1.0
+     * @access    private
+     */
+    var $_requiredNote = '<span style="font-size:80%; color:#ff0000;">*</span><span style="font-size:80%;"> denotes required field</span>';
+
+    /**
+     * Whether the form was submitted
+     * @var       boolean
+     * @access    private
+     */
+    var $_flagSubmitted = false;
+
+    // }}}
+    // {{{ constructor
+
+    /**
+     * Class constructor
+     * @param    string      $formName          Form's name.
+     * @param    string      $method            (optional)Form's method defaults to 'POST'
+     * @param    string      $action            (optional)Form's action
+     * @param    string      $target            (optional)Form's target defaults to '_self'
+     * @param    mixed       $attributes        (optional)Extra attributes for <form> tag
+     * @param    bool        $trackSubmit       (optional)Whether to track if the form was submitted by adding a special hidden field
+     * @access   public
+     */
+    function HTML_QuickForm($formName='', $method='post', $action='', $target='', $attributes=null, $trackSubmit = false)
+    {
+        HTML_Common::HTML_Common($attributes);
+        $method = (strtoupper($method) == 'GET') ? 'get' : 'post';
+        $action = ($action == '') ? $_SERVER['PHP_SELF'] : $action;
+        $target = empty($target) ? array() : array('target' => $target);
+        $attributes = array('action'=>$action, 'method'=>$method, 'name'=>$formName, 'id'=>$formName) + $target;
+        $this->updateAttributes($attributes);
+        if (!$trackSubmit || isset($_REQUEST['_qf__' . $formName])) {
+            if (1 == get_magic_quotes_gpc()) {
+                $this->_submitValues = $this->_recursiveFilter('stripslashes', 'get' == $method? $_GET: $_POST);
+                foreach ($_FILES as $keyFirst => $valFirst) {
+                    foreach ($valFirst as $keySecond => $valSecond) {
+                        if ('name' == $keySecond) {
+                            $this->_submitFiles[$keyFirst][$keySecond] = $this->_recursiveFilter('stripslashes', $valSecond);
+                        } else {
+                            $this->_submitFiles[$keyFirst][$keySecond] = $valSecond;
+                        }
+                    }
+                }
+            } else {
+                $this->_submitValues = 'get' == $method? $_GET: $_POST;
+                $this->_submitFiles  = $_FILES;
+            }
+            $this->_flagSubmitted = count($this->_submitValues) > 0 || count($this->_submitFiles) > 0;
+        }
+        if ($trackSubmit) {
+            unset($this->_submitValues['_qf__' . $formName]);
+            $this->addElement('hidden', '_qf__' . $formName, null);
+        }
+        if (preg_match('/^([0-9]+)([a-zA-Z]*)$/', ini_get('upload_max_filesize'), $matches)) {
+            // see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
+            switch (strtoupper($matches['2'])) {
+                case 'G':
+                    $this->_maxFileSize = $matches['1'] * 1073741824;
+                    break;
+                case 'M':
+                    $this->_maxFileSize = $matches['1'] * 1048576;
+                    break;
+                case 'K':
+                    $this->_maxFileSize = $matches['1'] * 1024;
+                    break;
+                default:
+                    $this->_maxFileSize = $matches['1'];
+            }
+        }
+    } // end constructor
+
+    // }}}
+    // {{{ apiVersion()
+
+    /**
+     * Returns the current API version
+     *
+     * @since     1.0
+     * @access    public
+     * @return    float
+     */
+    function apiVersion()
+    {
+        return 3.2;
+    } // end func apiVersion
+
+    // }}}
+    // {{{ registerElementType()
+
+    /**
+     * Registers a new element type
+     *
+     * @param     string    $typeName   Name of element type
+     * @param     string    $include    Include path for element type
+     * @param     string    $className  Element class name
+     * @since     1.0
+     * @access    public
+     * @return    void
+     */
+    function registerElementType($typeName, $include, $className)
+    {
+        $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($typeName)] = array($include, $className);
+    } // end func registerElementType
+
+    // }}}
+    // {{{ registerRule()
+
+    /**
+     * Registers a new validation rule
+     *
+     * @param     string    $ruleName   Name of validation rule
+     * @param     string    $type       Either: 'regex', 'function' or 'rule' for an HTML_QuickForm_Rule object
+     * @param     string    $data1      Name of function, regular expression or HTML_QuickForm_Rule classname
+     * @param     string    $data2      Object parent of above function or HTML_QuickForm_Rule file path
+     * @since     1.0
+     * @access    public
+     * @return    void
+     */
+    function registerRule($ruleName, $type, $data1, $data2 = null)
+    {
+        include_once('HTML/QuickForm/RuleRegistry.php');
+        $registry =& HTML_QuickForm_RuleRegistry::singleton();
+        $registry->registerRule($ruleName, $type, $data1, $data2);
+    } // end func registerRule
+
+    // }}}
+    // {{{ elementExists()
+
+    /**
+     * Returns true if element is in the form
+     *
+     * @param     string   $element         form name of element to check
+     * @since     1.0
+     * @access    public
+     * @return    boolean
+     */
+    function elementExists($element=null)
+    {
+        return isset($this->_elementIndex[$element]);
+    } // end func elementExists
+
+    // }}}
+    // {{{ setDatasource()
+
+    /**
+     * Sets a datasource object for this form object
+     *
+     * Datasource default and constant values will feed the QuickForm object if
+     * the datasource implements defaultValues() and constantValues() methods.
+     *
+     * @param     object   $datasource          datasource object implementing the informal datasource protocol
+     * @param     mixed    $defaultsFilter      string or array of filter(s) to apply to default values
+     * @param     mixed    $constantsFilter     string or array of filter(s) to apply to constants values
+     * @since     3.3
+     * @access    public
+     * @return    void
+     * @throws    HTML_QuickForm_Error
+     */
+    function setDatasource(&$datasource, $defaultsFilter = null, $constantsFilter = null)
+    {
+        if (is_object($datasource)) {
+            $this->_datasource =& $datasource;
+            if (is_callable(array($datasource, 'defaultValues'))) {
+                $this->setDefaults($datasource->defaultValues($this), $defaultsFilter);
+            }
+            if (is_callable(array($datasource, 'constantValues'))) {
+                $this->setConstants($datasource->constantValues($this), $constantsFilter);
+            }
+        } else {
+            return PEAR::raiseError(null, QUICKFORM_INVALID_DATASOURCE, null, E_USER_WARNING, "Datasource is not an object in QuickForm::setDatasource()", 'HTML_QuickForm_Error', true);
+        }
+    } // end func setDatasource
+
+    // }}}
+    // {{{ setDefaults()
+
+    /**
+     * Initializes default form values
+     *
+     * @param     array    $defaultValues       values used to fill the form
+     * @param     mixed    $filter              (optional) filter(s) to apply to all default values
+     * @since     1.0
+     * @access    public
+     * @return    void
+     * @throws    HTML_QuickForm_Error
+     */
+    function setDefaults($defaultValues = null, $filter = null)
+    {
+        if (is_array($defaultValues)) {
+            if (isset($filter)) {
+                if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
+                    foreach ($filter as $val) {
+                        if (!is_callable($val)) {
+                            return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
+                        } else {
+                            $defaultValues = $this->_recursiveFilter($val, $defaultValues);
+                        }
+                    }
+                } elseif (!is_callable($filter)) {
+                    return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
+                } else {
+                    $defaultValues = $this->_recursiveFilter($filter, $defaultValues);
+                }
+            }
+            $this->_defaultValues = HTML_QuickForm::arrayMerge($this->_defaultValues, $defaultValues);
+            foreach (array_keys($this->_elements) as $key) {
+                $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
+            }
+        }
+    } // end func setDefaults
+
+    // }}}
+    // {{{ setConstants()
+
+    /**
+     * Initializes constant form values.
+     * These values won't get overridden by POST or GET vars
+     *
+     * @param     array   $constantValues        values used to fill the form
+     * @param     mixed    $filter              (optional) filter(s) to apply to all default values
+     *
+     * @since     2.0
+     * @access    public
+     * @return    void
+     * @throws    HTML_QuickForm_Error
+     */
+    function setConstants($constantValues = null, $filter = null)
+    {
+        if (is_array($constantValues)) {
+            if (isset($filter)) {
+                if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
+                    foreach ($filter as $val) {
+                        if (!is_callable($val)) {
+                            return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
+                        } else {
+                            $constantValues = $this->_recursiveFilter($val, $constantValues);
+                        }
+                    }
+                } elseif (!is_callable($filter)) {
+                    return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
+                } else {
+                    $constantValues = $this->_recursiveFilter($filter, $constantValues);
+                }
+            }
+            $this->_constantValues = HTML_QuickForm::arrayMerge($this->_constantValues, $constantValues);
+            foreach (array_keys($this->_elements) as $key) {
+                $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
+            }
+        }
+    } // end func setConstants
+
+    // }}}
+    // {{{ setMaxFileSize()
+
+    /**
+     * Sets the value of MAX_FILE_SIZE hidden element
+     *
+     * @param     int    $bytes    Size in bytes
+     * @since     3.0
+     * @access    public
+     * @return    void
+     */
+    function setMaxFileSize($bytes = 0)
+    {
+        if ($bytes > 0) {
+            $this->_maxFileSize = $bytes;
+        }
+        if (!$this->elementExists('MAX_FILE_SIZE')) {
+            $this->addElement('hidden', 'MAX_FILE_SIZE', $this->_maxFileSize);
+        } else {
+            $el =& $this->getElement('MAX_FILE_SIZE');
+            $el->updateAttributes(array('value' => $this->_maxFileSize));
+        }
+    } // end func setMaxFileSize
+
+    // }}}
+    // {{{ getMaxFileSize()
+
+    /**
+     * Returns the value of MAX_FILE_SIZE hidden element
+     *
+     * @since     3.0
+     * @access    public
+     * @return    int   max file size in bytes
+     */
+    function getMaxFileSize()
+    {
+        return $this->_maxFileSize;
+    } // end func getMaxFileSize
+
+    // }}}
+    // {{{ &createElement()
+
+    /**
+     * Creates a new form element of the given type.
+     *
+     * This method accepts variable number of parameters, their
+     * meaning and count depending on $elementType
+     *
+     * @param     string     $elementType    type of element to add (text, textarea, file...)
+     * @since     1.0
+     * @access    public
+     * @return    HTML_QuickForm_Element
+     * @throws    HTML_QuickForm_Error
+     */
+    function &createElement($elementType)
+    {
+        $args    =  func_get_args();
+        $element =& HTML_QuickForm::_loadElement('createElement', $elementType, array_slice($args, 1), null);
+        return $element;
+    } // end func createElement
+
+    // }}}
+    // {{{ _loadElement()
+
+    /**
+     * Returns a form element of the given type
+     *
+     * @param     string   $event   event to send to newly created element ('createElement' or 'addElement')
+     * @param     string   $type    element type
+     * @param     array    $args    arguments for event
+     * @since     2.0
+     * @access    private
+     * @return    HTML_QuickForm_Element
+     * @throws    HTML_QuickForm_Error
+     */
+    function &_loadElement($event, $type, $args, $form)
+    {
+        $type = strtolower($type);
+        if (!HTML_QuickForm::isTypeRegistered($type)) {
+            $error = PEAR::raiseError(null, QUICKFORM_UNREGISTERED_ELEMENT, null, E_USER_WARNING, "Element '$type' does not exist in HTML_QuickForm::_loadElement()", 'HTML_QuickForm_Error', true);
+            return $error;
+        }
+        $className = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][1];
+        $includeFile = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][0];
+        include_once($includeFile);
+        $elementObject = new $className();
+        for ($i = 0; $i < 5; $i++) {
+            if (!isset($args[$i])) {
+                $args[$i] = null;
+            }
+        }
+        $err = $elementObject->onQuickFormEvent($event, $args, $form);
+        if ($err !== true) {
+            return $err;
+        }
+        return $elementObject;
+    } // end func _loadElement
+
+    // }}}
+    // {{{ addElement()
+
+    /**
+     * Adds an element into the form
+     *
+     * If $element is a string representing element type, then this
+     * method accepts variable number of parameters, their meaning
+     * and count depending on $element
+     *
+     * @param    mixed      $element        element object or type of element to add (text, textarea, file...)
+     * @since    1.0
+     * @return   HTML_QuickForm_Element     a reference to newly added element
+     * @access   public
+     * @throws   HTML_QuickForm_Error
+     */
+    function &addElement($element)
+    {
+        if (is_object($element) && is_subclass_of($element, 'html_quickform_element')) {
+           $elementObject = &$element;
+           $elementObject->onQuickFormEvent('updateValue', null, $this);
+        } else {
+            $args = func_get_args();
+            $elementObject =& $this->_loadElement('addElement', $element, array_slice($args, 1), $this);
+            if (PEAR::isError($elementObject)) {
+                return $elementObject;
+            }
+        }
+        $elementName = $elementObject->getName();
+
+        // Add the element if it is not an incompatible duplicate
+        if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
+            if ($this->_elements[$this->_elementIndex[$elementName]]->getType() ==
+                $elementObject->getType()) {
+                $this->_elements[] =& $elementObject;
+                $elKeys = array_keys($this->_elements);
+                $this->_duplicateIndex[$elementName][] = end($elKeys);
+            } else {
+                $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::addElement()", 'HTML_QuickForm_Error', true);
+                return $error;
+            }
+        } else {
+            $this->_elements[] =& $elementObject;
+            $elKeys = array_keys($this->_elements);
+            $this->_elementIndex[$elementName] = end($elKeys);
+        }
+        if ($this->_freezeAll) {
+            $elementObject->freeze();
+        }
+
+        return $elementObject;
+    } // end func addElement
+
+    // }}}
+    // {{{ insertElementBefore()
+
+   /**
+    * Inserts a new element right before the other element
+    *
+    * Warning: it is not possible to check whether the $element is already
+    * added to the form, therefore if you want to move the existing form
+    * element to a new position, you'll have to use removeElement():
+    * $form->insertElementBefore($form->removeElement('foo', false), 'bar');
+    *
+    * @access   public
+    * @since    3.2.4
+    * @param    HTML_QuickForm_element  Element to insert
+    * @param    string                  Name of the element before which the new
+    *                                   one is inserted
+    * @return   HTML_QuickForm_element  reference to inserted element
+    * @throws   HTML_QuickForm_Error
+    */
+    function &insertElementBefore(&$element, $nameAfter)
+    {
+        if (!empty($this->_duplicateIndex[$nameAfter])) {
+            $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, 'Several elements named "' . $nameAfter . '" exist in HTML_QuickForm::insertElementBefore().', 'HTML_QuickForm_Error', true);
+            return $error;
+        } elseif (!$this->elementExists($nameAfter)) {
+            $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$nameAfter' does not exist in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
+            return $error;
+        }
+        $elementName = $element->getName();
+        $targetIdx   = $this->_elementIndex[$nameAfter];
+        $duplicate   = false;
+        // Like in addElement(), check that it's not an incompatible duplicate
+        if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
+            if ($this->_elements[$this->_elementIndex[$elementName]]->getType() != $element->getType()) {
+                $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
+                return $error;
+            }
+            $duplicate = true;
+        }
+        // Move all the elements after added back one place, reindex _elementIndex and/or _duplicateIndex
+        $elKeys = array_keys($this->_elements);
+        for ($i = end($elKeys); $i >= $targetIdx; $i--) {
+            if (isset($this->_elements[$i])) {
+                $currentName = $this->_elements[$i]->getName();
+                $this->_elements[$i + 1] =& $this->_elements[$i];
+                if ($this->_elementIndex[$currentName] == $i) {
+                    $this->_elementIndex[$currentName] = $i + 1;
+                } else {
+                    $dupIdx = array_search($i, $this->_duplicateIndex[$currentName]);
+                    $this->_duplicateIndex[$currentName][$dupIdx] = $i + 1;
+                }
+                unset($this->_elements[$i]);
+            }
+        }
+        // Put the element in place finally
+        $this->_elements[$targetIdx] =& $element;
+        if (!$duplicate) {
+            $this->_elementIndex[$elementName] = $targetIdx;
+        } else {
+            $this->_duplicateIndex[$elementName][] = $targetIdx;
+        }
+        $element->onQuickFormEvent('updateValue', null, $this);
+        if ($this->_freezeAll) {
+            $element->freeze();
+        }
+        // If not done, the elements will appear in reverse order
+        ksort($this->_elements);
+        return $element;
+    }
+
+    // }}}
+    // {{{ addGroup()
+
+    /**
+     * Adds an element group
+     * @param    array      $elements       array of elements composing the group
+     * @param    string     $name           (optional)group name
+     * @param    string     $groupLabel     (optional)group label
+     * @param    string     $separator      (optional)string to separate elements
+     * @param    string     $appendName     (optional)specify whether the group name should be
+     *                                      used in the form element name ex: group[element]
+     * @return   HTML_QuickForm_group       reference to a newly added group
+     * @since    2.8
+     * @access   public
+     * @throws   HTML_QuickForm_Error
+     */
+    function &addGroup($elements, $name=null, $groupLabel='', $separator=null, $appendName = true)
+    {
+        static $anonGroups = 1;
+
+        if (0 == strlen($name)) {
+            $name       = 'qf_group_' . $anonGroups++;
+            $appendName = false;
+        }
+        $group =& $this->addElement('group', $name, $groupLabel, $elements, $separator, $appendName);
+        return $group;
+    } // end func addGroup
+
+    // }}}
+    // {{{ &getElement()
+
+    /**
+     * Returns a reference to the element
+     *
+     * @param     string     $element    Element name
+     * @since     2.0
+     * @access    public
+     * @return    HTML_QuickForm_element    reference to element
+     * @throws    HTML_QuickForm_Error
+     */
+    function &getElement($element)
+    {
+        if (isset($this->_elementIndex[$element])) {
+            return $this->_elements[$this->_elementIndex[$element]];
+        } else {
+            $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElement()", 'HTML_QuickForm_Error', true);
+            return $error;
+        }
+    } // end func getElement
+
+    // }}}
+    // {{{ &getElementValue()
+
+    /**
+     * Returns the element's raw value
+     *
+     * This returns the value as submitted by the form (not filtered)
+     * or set via setDefaults() or setConstants()
+     *
+     * @param     string     $element    Element name
+     * @since     2.0
+     * @access    public
+     * @return    mixed     element value
+     * @throws    HTML_QuickForm_Error
+     */
+    function &getElementValue($element)
+    {
+        if (!isset($this->_elementIndex[$element])) {
+            $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
+            return $error;
+        }
+        $value = $this->_elements[$this->_elementIndex[$element]]->getValue();
+        if (isset($this->_duplicateIndex[$element])) {
+            foreach ($this->_duplicateIndex[$element] as $index) {
+                if (null !== ($v = $this->_elements[$index]->getValue())) {
+                    if (is_array($value)) {
+                        $value[] = $v;
+                    } else {
+                        $value = (null === $value)? $v: array($value, $v);
+                    }
+                }
+            }
+        }
+        return $value;
+    } // end func getElementValue
+
+    // }}}
+    // {{{ getSubmitValue()
+
+    /**
+     * Returns the elements value after submit and filter
+     *
+     * @param     string     Element name
+     * @since     2.0
+     * @access    public
+     * @return    mixed     submitted element value or null if not set
+     */
+    function getSubmitValue($elementName)
+    {
+        $value = null;
+        if (isset($this->_submitValues[$elementName]) || isset($this->_submitFiles[$elementName])) {
+            $value = isset($this->_submitValues[$elementName])? $this->_submitValues[$elementName]: array();
+            if (is_array($value) && isset($this->_submitFiles[$elementName])) {
+                foreach ($this->_submitFiles[$elementName] as $k => $v) {
+                    $value = HTML_QuickForm::arrayMerge($value, $this->_reindexFiles($this->_submitFiles[$elementName][$k], $k));
+                }
+            }
+
+        } elseif ('file' == $this->getElementType($elementName)) {
+            return $this->getElementValue($elementName);
+
+        } elseif (false !== ($pos = strpos($elementName, '['))) {
+            $base = str_replace(
+                        array('\\', '\''), array('\\\\', '\\\''),
+                        substr($elementName, 0, $pos)
+                    );
+
+            $keys = str_replace(
+                array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
+                substr($elementName, $pos + 1, -1)
+                );
+            $idx  = "['" . $keys . "']";
+            $keyArray = explode("']['", $keys);
+
+            if (isset($this->_submitValues[$base])) {
+                $value = HTML_QuickForm_utils::recursiveValue($this->_submitValues[$base], $keyArray, NULL);
+            }
+
+            if ((is_array($value) || null === $value) && isset($this->_submitFiles[$base])) {
+                $props = array('name', 'type', 'size', 'tmp_name', 'error');
+                $code  = "if (!isset(\$this->_submitFiles['{$base}']['name']{$idx})) {\n" .
+                         "    return null;\n" .
+                         "} else {\n" .
+                         "    \$v = array();\n";
+                foreach ($props as $prop) {
+                    $code .= "    \$v = HTML_QuickForm::arrayMerge(\$v, \$this->_reindexFiles(\$this->_submitFiles['{$base}']['{$prop}']{$idx}, '{$prop}'));\n";
+                }
+                $fileValue = eval($code . "    return \$v;\n}\n");
+                if (null !== $fileValue) {
+                    $value = null === $value? $fileValue: HTML_QuickForm::arrayMerge($value, $fileValue);
+                }
+            }
+        }
+
+        // This is only supposed to work for groups with appendName = false
+        if (null === $value && 'group' == $this->getElementType($elementName)) {
+            $group    =& $this->getElement($elementName);
+            $elements =& $group->getElements();
+            foreach (array_keys($elements) as $key) {
+                $name = $group->getElementName($key);
+                // prevent endless recursion in case of radios and such
+                if ($name != $elementName) {
+                    if (null !== ($v = $this->getSubmitValue($name))) {
+                        $value[$name] = $v;
+                    }
+                }
+            }
+        }
+        return $value;
+    } // end func getSubmitValue
+
+    // }}}
+    // {{{ _reindexFiles()
+
+   /**
+    * A helper function to change the indexes in $_FILES array
+    *
+    * @param  mixed   Some value from the $_FILES array
+    * @param  string  The key from the $_FILES array that should be appended
+    * @return array
+    */
+    function _reindexFiles($value, $key)
+    {
+        if (!is_array($value)) {
+            return array($key => $value);
+        } else {
+            $ret = array();
+            foreach ($value as $k => $v) {
+                $ret[$k] = $this->_reindexFiles($v, $key);
+            }
+            return $ret;
+        }
+    }
+
+    // }}}
+    // {{{ getElementError()
+
+    /**
+     * Returns error corresponding to validated element
+     *
+     * @param     string    $element        Name of form element to check
+     * @since     1.0
+     * @access    public
+     * @return    string    error message corresponding to checked element
+     */
+    function getElementError($element)
+    {
+        if (isset($this->_errors[$element])) {
+            return $this->_errors[$element];
+        }
+    } // end func getElementError
+
+    // }}}
+    // {{{ setElementError()
+
+    /**
+     * Set error message for a form element
+     *
+     * @param     string    $element    Name of form element to set error for
+     * @param     string    $message    Error message, if empty then removes the current error message
+     * @since     1.0
+     * @access    public
+     * @return    void
+     */
+    function setElementError($element, $message = null)
+    {
+        if (!empty($message)) {
+            $this->_errors[$element] = $message;
+        } else {
+            unset($this->_errors[$element]);
+        }
+    } // end func setElementError
+
+     // }}}
+     // {{{ getElementType()
+
+     /**
+      * Returns the type of the given element
+      *
+      * @param      string    $element    Name of form element
+      * @since      1.1
+      * @access     public
+      * @return     string    Type of the element, false if the element is not found
+      */
+     function getElementType($element)
+     {
+         if (isset($this->_elementIndex[$element])) {
+             return $this->_elements[$this->_elementIndex[$element]]->getType();
+         }
+         return false;
+     } // end func getElementType
+
+     // }}}
+     // {{{ updateElementAttr()
+
+    /**
+     * Updates Attributes for one or more elements
+     *
+     * @param      mixed    $elements   Array of element names/objects or string of elements to be updated
+     * @param      mixed    $attrs      Array or sting of html attributes
+     * @since      2.10
+     * @access     public
+     * @return     void
+     */
+    function updateElementAttr($elements, $attrs)
+    {
+        if (is_string($elements)) {
+            $elements = preg_split('/[ ]?,[ ]?/', $elements);
+        }
+        foreach (array_keys($elements) as $key) {
+            if (is_object($elements[$key]) && is_a($elements[$key], 'HTML_QuickForm_element')) {
+                $elements[$key]->updateAttributes($attrs);
+            } elseif (isset($this->_elementIndex[$elements[$key]])) {
+                $this->_elements[$this->_elementIndex[$elements[$key]]]->updateAttributes($attrs);
+                if (isset($this->_duplicateIndex[$elements[$key]])) {
+                    foreach ($this->_duplicateIndex[$elements[$key]] as $index) {
+                        $this->_elements[$index]->updateAttributes($attrs);
+                    }
+                }
+            }
+        }
+    } // end func updateElementAttr
+
+    // }}}
+    // {{{ removeElement()
+
+    /**
+     * Removes an element
+     *
+     * The method "unlinks" an element from the form, returning the reference
+     * to the element object. If several elements named $elementName exist,
+     * it removes the first one, leaving the others intact.
+     *
+     * @param string    $elementName The element name
+     * @param boolean   $removeRules True if rules for this element are to be removed too
+     * @access public
+     * @since 2.0
+     * @return HTML_QuickForm_element    a reference to the removed element
+     * @throws HTML_QuickForm_Error
+     */
+    function &removeElement($elementName, $removeRules = true)
+    {
+        if (!isset($this->_elementIndex[$elementName])) {
+            $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$elementName' does not exist in HTML_QuickForm::removeElement()", 'HTML_QuickForm_Error', true);
+            return $error;
+        }
+        $el =& $this->_elements[$this->_elementIndex[$elementName]];
+        unset($this->_elements[$this->_elementIndex[$elementName]]);
+        if (empty($this->_duplicateIndex[$elementName])) {
+            unset($this->_elementIndex[$elementName]);
+        } else {
+            $this->_elementIndex[$elementName] = array_shift($this->_duplicateIndex[$elementName]);
+        }
+        if ($removeRules) {
+            $this->_required = array_diff($this->_required, array($elementName));
+            unset($this->_rules[$elementName], $this->_errors[$elementName]);
+            if ('group' == $el->getType()) {
+                foreach (array_keys($el->getElements()) as $key) {
+                    unset($this->_rules[$el->getElementName($key)]);
+                }
+            }
+        }
+        return $el;
+    } // end func removeElement
+
+    // }}}
+    // {{{ addRule()
+
+    /**
+     * Adds a validation rule for the given field
+     *
+     * If the element is in fact a group, it will be considered as a whole.
+     * To validate grouped elements as separated entities,
+     * use addGroupRule instead of addRule.
+     *
+     * @param    string     $element       Form element name
+     * @param    string     $message       Message to display for invalid data
+     * @param    string     $type          Rule type, use getRegisteredRules() to get types
+     * @param    string     $format        (optional)Required for extra rule data
+     * @param    string     $validation    (optional)Where to perform validation: "server", "client"
+     * @param    boolean    $reset         Client-side validation: reset the form element to its original value if there is an error?
+     * @param    boolean    $force         Force the rule to be applied, even if the target form element does not exist
+     * @since    1.0
+     * @access   public
+     * @throws   HTML_QuickForm_Error
+     */
+    function addRule($element, $message, $type, $format=null, $validation='server', $reset = false, $force = false)
+    {
+        if (!$force) {
+            if (!is_array($element) && !$this->elementExists($element)) {
+                return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
+            } elseif (is_array($element)) {
+                foreach ($element as $el) {
+                    if (!$this->elementExists($el)) {
+                        return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$el' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
+                    }
+                }
+            }
+        }
+        if (false === ($newName = $this->isRuleRegistered($type, true))) {
+            return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
+        } elseif (is_string($newName)) {
+            $type = $newName;
+        }
+        if (is_array($element)) {
+            $dependent = $element;
+            $element   = array_shift($dependent);
+        } else {
+            $dependent = null;
+        }
+        if ($type == 'required' || $type == 'uploadedfile') {
+            $this->_required[] = $element;
+        }
+        if (!isset($this->_rules[$element])) {
+            $this->_rules[$element] = array();
+        }
+        if ($validation == 'client') {
+            $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
+        }
+        $this->_rules[$element][] = array(
+            'type'        => $type,
+            'format'      => $format,
+            'message'     => $message,
+            'validation'  => $validation,
+            'reset'       => $reset,
+            'dependent'   => $dependent
+        );
+    } // end func addRule
+
+    // }}}
+    // {{{ addGroupRule()
+
+    /**
+     * Adds a validation rule for the given group of elements
+     *
+     * Only groups with a name can be assigned a validation rule
+     * Use addGroupRule when you need to validate elements inside the group.
+     * Use addRule if you need to validate the group as a whole. In this case,
+     * the same rule will be applied to all elements in the group.
+     * Use addRule if you need to validate the group against a function.
+     *
+     * @param    string     $group         Form group name
+     * @param    mixed      $arg1          Array for multiple elements or error message string for one element
+     * @param    string     $type          (optional)Rule type use getRegisteredRules() to get types
+     * @param    string     $format        (optional)Required for extra rule data
+     * @param    int        $howmany       (optional)How many valid elements should be in the group
+     * @param    string     $validation    (optional)Where to perform validation: "server", "client"
+     * @param    bool       $reset         Client-side: whether to reset the element's value to its original state if validation failed.
+     * @since    2.5
+     * @access   public
+     * @throws   HTML_QuickForm_Error
+     */
+    function addGroupRule($group, $arg1, $type='', $format=null, $howmany=0, $validation = 'server', $reset = false)
+    {
+        if (!$this->elementExists($group)) {
+            return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Group '$group' does not exist in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
+        }
+
+        $groupObj =& $this->getElement($group);
+        if (is_array($arg1)) {
+            $required = 0;
+            foreach ($arg1 as $elementIndex => $rules) {
+                $elementName = $groupObj->getElementName($elementIndex);
+                foreach ($rules as $rule) {
+                    $format = (isset($rule[2])) ? $rule[2] : null;
+                    $validation = (isset($rule[3]) && 'client' == $rule[3])? 'client': 'server';
+                    $reset = isset($rule[4]) && $rule[4];
+                    $type = $rule[1];
+                    if (false === ($newName = $this->isRuleRegistered($type, true))) {
+                        return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
+                    } elseif (is_string($newName)) {
+                        $type = $newName;
+                    }
+
+                    $this->_rules[$elementName][] = array(
+                                                        'type'        => $type,
+                                                        'format'      => $format,
+                                                        'message'     => $rule[0],
+                                                        'validation'  => $validation,
+                                                        'reset'       => $reset,
+                                                        'group'       => $group);
+
+                    if ('required' == $type || 'uploadedfile' == $type) {
+                        $groupObj->_required[] = $elementName;
+                        $this->_required[] = $elementName;
+                        $required++;
+                    }
+                    if ('client' == $validation) {
+                        $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
+                    }
+                }
+            }
+            if ($required > 0 && count($groupObj->getElements()) == $required) {
+                $this->_required[] = $group;
+            }
+        } elseif (is_string($arg1)) {
+            if (false === ($newName = $this->isRuleRegistered($type, true))) {
+                return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
+            } elseif (is_string($newName)) {
+                $type = $newName;
+            }
+
+            // addGroupRule() should also handle <select multiple>
+            if (is_a($groupObj, 'html_quickform_group')) {
+                // Radios need to be handled differently when required
+                if ($type == 'required' && $groupObj->getGroupType() == 'radio') {
+                    $howmany = ($howmany == 0) ? 1 : $howmany;
+                } else {
+                    $howmany = ($howmany == 0) ? count($groupObj->getElements()) : $howmany;
+                }
+            }
+
+            $this->_rules[$group][] = array('type'       => $type,
+                                            'format'     => $format,
+                                            'message'    => $arg1,
+                                            'validation' => $validation,
+                                            'howmany'    => $howmany,
+                                            'reset'      => $reset);
+            if ($type == 'required') {
+                $this->_required[] = $group;
+            }
+            if ($validation == 'client') {
+                $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
+            }
+        }
+    } // end func addGroupRule
+
+    // }}}
+    // {{{ addFormRule()
+
+   /**
+    * Adds a global validation rule
+    *
+    * This should be used when for a rule involving several fields or if
+    * you want to use some completely custom validation for your form.
+    * The rule function/method should return true in case of successful
+    * validation and array('element name' => 'error') when there were errors.
+    *
+    * @access   public
+    * @param    mixed   Callback, either function name or array(&$object, 'method')
+    * @throws   HTML_QuickForm_Error
+    */
+    function addFormRule($rule)
+    {
+        if (!is_callable($rule)) {
+            return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, 'Callback function does not exist in HTML_QuickForm::addFormRule()', 'HTML_QuickForm_Error', true);
+        }
+        $this->_formRules[] = $rule;
+    }
+
+    // }}}
+    // {{{ applyFilter()
+
+    /**
+     * Applies a data filter for the given field(s)
+     *
+     * @param    mixed     $element       Form element name or array of such names
+     * @param    mixed     $filter        Callback, either function name or array(&$object, 'method')
+     * @since    2.0
+     * @access   public
+     * @throws   HTML_QuickForm_Error
+     */
+    function applyFilter($element, $filter)
+    {
+        if (!is_callable($filter)) {
+            return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::applyFilter()", 'HTML_QuickForm_Error', true);
+        }
+        if ($element == '__ALL__') {
+            $this->_submitValues = $this->_recursiveFilter($filter, $this->_submitValues);
+        } else {
+            if (!is_array($element)) {
+                $element = array($element);
+            }
+            foreach ($element as $elName) {
+                $value = $this->getSubmitValue($elName);
+                if (null !== $value) {
+                    if (false === strpos($elName, '[')) {
+                        $this->_submitValues[$elName] = $this->_recursiveFilter($filter, $value);
+                    } else {
+                        $idx  = "['" . str_replace(
+                                    array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
+                                    $elName
+                                ) . "']";
+                        eval("\$this->_submitValues{$idx} = \$this->_recursiveFilter(\$filter, \$value);");
+                    }
+                }
+            }
+        }
+    } // end func applyFilter
+
+    // }}}
+    // {{{ _recursiveFilter()
+
+    /**
+     * Recursively apply a filter function
+     *
+     * @param     string   $filter    filter to apply
+     * @param     mixed    $value     submitted values
+     * @since     2.0
+     * @access    private
+     * @return    cleaned values
+     */
+    function _recursiveFilter($filter, $value)
+    {
+        if (is_array($value)) {
+            $cleanValues = array();
+            foreach ($value as $k => $v) {
+                $cleanValues[$k] = $this->_recursiveFilter($filter, $v);
+            }
+            return $cleanValues;
+        } else {
+            return call_user_func($filter, $value);
+        }
+    } // end func _recursiveFilter
+
+    // }}}
+    // {{{ arrayMerge()
+
+   /**
+    * Merges two arrays
+    *
+    * Merges two array like the PHP function array_merge but recursively.
+    * The main difference is that existing keys will not be renumbered
+    * if they are integers.
+    *
+    * @access   public
+    * @param    array   $a  original array
+    * @param    array   $b  array which will be merged into first one
+    * @return   array   merged array
+    */
+    function arrayMerge($a, $b)
+    {
+        foreach ($b as $k => $v) {
+            if (is_array($v)) {
+                if (isset($a[$k]) && !is_array($a[$k])) {
+                    $a[$k] = $v;
+                } else {
+                    if (!isset($a[$k])) {
+                        $a[$k] = array();
+                    }
+                    $a[$k] = HTML_QuickForm::arrayMerge($a[$k], $v);
+                }
+            } else {
+                $a[$k] = $v;
+            }
+        }
+        return $a;
+    } // end func arrayMerge
+
+    // }}}
+    // {{{ isTypeRegistered()
+
+    /**
+     * Returns whether or not the form element type is supported
+     *
+     * @param     string   $type     Form element type
+     * @since     1.0
+     * @access    public
+     * @return    boolean
+     */
+    function isTypeRegistered($type)
+    {
+        return isset($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($type)]);
+    } // end func isTypeRegistered
+
+    // }}}
+    // {{{ getRegisteredTypes()
+
+    /**
+     * Returns an array of registered element types
+     *
+     * @since     1.0
+     * @access    public
+     * @return    array
+     */
+    function getRegisteredTypes()
+    {
+        return array_keys($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']);
+    } // end func getRegisteredTypes
+
+    // }}}
+    // {{{ isRuleRegistered()
+
+    /**
+     * Returns whether or not the given rule is supported
+     *
+     * @param     string   $name    Validation rule name
+     * @param     bool     Whether to automatically register subclasses of HTML_QuickForm_Rule
+     * @since     1.0
+     * @access    public
+     * @return    mixed    true if previously registered, false if not, new rule name if auto-registering worked
+     */
+    function isRuleRegistered($name, $autoRegister = false)
+    {
+        if (is_scalar($name) && isset($GLOBALS['_HTML_QuickForm_registered_rules'][$name])) {
+            return true;
+        } elseif (!$autoRegister) {
+            return false;
+        }
+        // automatically register the rule if requested
+        include_once 'HTML/QuickForm/RuleRegistry.php';
+        $ruleName = false;
+        if (is_object($name) && is_a($name, 'html_quickform_rule')) {
+            $ruleName = !empty($name->name)? $name->name: strtolower(get_class($name));
+        } elseif (is_string($name) && class_exists($name)) {
+            $parent = strtolower($name);
+            do {
+                if ('html_quickform_rule' == strtolower($parent)) {
+                    $ruleName = strtolower($name);
+                    break;
+                }
+            } while ($parent = get_parent_class($parent));
+        }
+        if ($ruleName) {
+            $registry =& HTML_QuickForm_RuleRegistry::singleton();
+            $registry->registerRule($ruleName, null, $name);
+        }
+        return $ruleName;
+    } // end func isRuleRegistered
+
+    // }}}
+    // {{{ getRegisteredRules()
+
+    /**
+     * Returns an array of registered validation rules
+     *
+     * @since     1.0
+     * @access    public
+     * @return    array
+     */
+    function getRegisteredRules()
+    {
+        return array_keys($GLOBALS['_HTML_QuickForm_registered_rules']);
+    } // end func getRegisteredRules
+
+    // }}}
+    // {{{ isElementRequired()
+
+    /**
+     * Returns whether or not the form element is required
+     *
+     * @param     string   $element     Form element name
+     * @since     1.0
+     * @access    public
+     * @return    boolean
+     */
+    function isElementRequired($element)
+    {
+        return in_array($element, $this->_required, true);
+    } // end func isElementRequired
+
+    // }}}
+    // {{{ isElementFrozen()
+
+    /**
+     * Returns whether or not the form element is frozen
+     *
+     * @param     string   $element     Form element name
+     * @since     1.0
+     * @access    public
+     * @return    boolean
+     */
+    function isElementFrozen($element)
+    {
+         if (isset($this->_elementIndex[$element])) {
+             return $this->_elements[$this->_elementIndex[$element]]->isFrozen();
+         }
+         return false;
+    } // end func isElementFrozen
+
+    // }}}
+    // {{{ setJsWarnings()
+
+    /**
+     * Sets JavaScript warning messages
+     *
+     * @param     string   $pref        Prefix warning
+     * @param     string   $post        Postfix warning
+     * @since     1.1
+     * @access    public
+     * @return    void
+     */
+    function setJsWarnings($pref, $post)
+    {
+        $this->_jsPrefix = $pref;
+        $this->_jsPostfix = $post;
+    } // end func setJsWarnings
+
+    // }}}
+    // {{{ setRequiredNote()
+
+    /**
+     * Sets required-note
+     *
+     * @param     string   $note        Message indicating some elements are required
+     * @since     1.1
+     * @access    public
+     * @return    void
+     */
+    function setRequiredNote($note)
+    {
+        $this->_requiredNote = $note;
+    } // end func setRequiredNote
+
+    // }}}
+    // {{{ getRequiredNote()
+
+    /**
+     * Returns the required note
+     *
+     * @since     2.0
+     * @access    public
+     * @return    string
+     */
+    function getRequiredNote()
+    {
+        return $this->_requiredNote;
+    } // end func getRequiredNote
+
+    // }}}
+    // {{{ validate()
+
+    /**
+     * Performs the server side validation
+     * @access    public
+     * @since     1.0
+     * @return    boolean   true if no error found
+     * @throws    HTML_QuickForm_Error
+     */
+    function validate()
+    {
+        if (count($this->_rules) == 0 && count($this->_formRules) == 0 &&
+            $this->isSubmitted()) {
+            return (0 == count($this->_errors));
+        } elseif (!$this->isSubmitted()) {
+            return false;
+        }
+
+        include_once('HTML/QuickForm/RuleRegistry.php');
+        $registry =& HTML_QuickForm_RuleRegistry::singleton();
+
+        foreach ($this->_rules as $target => $rules) {
+            $submitValue = $this->getSubmitValue($target);
+
+            foreach ($rules as $rule) {
+                if ((isset($rule['group']) && isset($this->_errors[$rule['group']])) ||
+                     isset($this->_errors[$target])) {
+                    continue 2;
+                }
+                // If element is not required and is empty, we shouldn't validate it
+                if (!$this->isElementRequired($target)) {
+                    if (!isset($submitValue) || '' == $submitValue) {
+                        continue 2;
+                    // Fix for bug #3501: we shouldn't validate not uploaded files, either.
+                    // Unfortunately, we can't just use $element->isUploadedFile() since
+                    // the element in question can be buried in group. Thus this hack.
+                    // See also bug #12014, we should only consider a file that has
+                    // status UPLOAD_ERR_NO_FILE as not uploaded, in all other cases
+                    // validation should be performed, so that e.g. 'maxfilesize' rule
+                    // will display an error if status is UPLOAD_ERR_INI_SIZE
+                    // or UPLOAD_ERR_FORM_SIZE
+                    } elseif (is_array($submitValue)) {
+                        if (false === ($pos = strpos($target, '['))) {
+                            $isUpload = !empty($this->_submitFiles[$target]);
+                        } else {
+                            $base = str_replace(
+                                        array('\\', '\''), array('\\\\', '\\\''),
+                                        substr($target, 0, $pos)
+                                    );
+                            $idx  = "['" . str_replace(
+                                        array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
+                                        substr($target, $pos + 1, -1)
+                                    ) . "']";
+                            eval("\$isUpload = isset(\$this->_submitFiles['{$base}']['name']{$idx});");
+                        }
+                        if ($isUpload && (!isset($submitValue['error']) || UPLOAD_ERR_NO_FILE == $submitValue['error'])) {
+                            continue 2;
+                        }
+                    }
+                }
+                if (isset($rule['dependent']) && is_array($rule['dependent'])) {
+                    $values = array($submitValue);
+                    foreach ($rule['dependent'] as $elName) {
+                        $values[] = $this->getSubmitValue($elName);
+                    }
+                    $result = $registry->validate($rule['type'], $values, $rule['format'], true);
+                } elseif (is_array($submitValue) && !isset($rule['howmany'])) {
+                    $result = $registry->validate($rule['type'], $submitValue, $rule['format'], true);
+                } else {
+                    $result = $registry->validate($rule['type'], $submitValue, $rule['format'], false);
+                }
+
+                if (!$result || (!empty($rule['howmany']) && $rule['howmany'] > (int)$result)) {
+                    if (isset($rule['group'])) {
+                        $this->_errors[$rule['group']] = $rule['message'];
+                    } else {
+                        $this->_errors[$target] = $rule['message'];
+                    }
+                }
+            }
+        }
+
+        // process the global rules now
+        foreach ($this->_formRules as $rule) {
+            if (true !== ($res = call_user_func($rule, $this->_submitValues, $this->_submitFiles))) {
+                if (is_array($res)) {
+                    $this->_errors += $res;
+                } else {
+                    return PEAR::raiseError(null, QUICKFORM_ERROR, null, E_USER_WARNING, 'Form rule callback returned invalid value in HTML_QuickForm::validate()', 'HTML_QuickForm_Error', true);
+                }
+            }
+        }
+
+        return (0 == count($this->_errors));
+    } // end func validate
+
+    // }}}
+    // {{{ freeze()
+
+    /**
+     * Displays elements without HTML input tags
+     *
+     * @param    mixed   $elementList       array or string of element(s) to be frozen
+     * @since     1.0
+     * @access   public
+     * @throws   HTML_QuickForm_Error
+     */
+    function freeze($elementList=null)
+    {
+        if (!isset($elementList)) {
+            $this->_freezeAll = true;
+            $elementList = array();
+        } else {
+            if (!is_array($elementList)) {
+                $elementList = preg_split('/[ ]*,[ ]*/', $elementList);
+            }
+            $elementList = array_flip($elementList);
+        }
+
+        foreach (array_keys($this->_elements) as $key) {
+            $name = $this->_elements[$key]->getName();
+            if ($this->_freezeAll || isset($elementList[$name])) {
+                $this->_elements[$key]->freeze();
+                unset($elementList[$name]);
+            }
+        }
+
+        if (!empty($elementList)) {
+            return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Nonexistant element(s): '" . implode("', '", array_keys($elementList)) . "' in HTML_QuickForm::freeze()", 'HTML_QuickForm_Error', true);
+        }
+        return true;
+    } // end func freeze
+
+    // }}}
+    // {{{ isFrozen()
+
+    /**
+     * Returns whether or not the whole form is frozen
+     *
+     * @since     3.0
+     * @access    public
+     * @return    boolean
+     */
+    function isFrozen()
+    {
+         return $this->_freezeAll;
+    } // end func isFrozen
+
+    // }}}
+    // {{{ process()
+
+    /**
+     * Performs the form data processing
+     *
+     * @param    mixed     $callback        Callback, either function name or array(&$object, 'method')
+     * @param    bool      $mergeFiles      Whether uploaded files should be processed too
+     * @since    1.0
+     * @access   public
+     * @throws   HTML_QuickForm_Error
+     * @return   mixed     Whatever value the $callback function returns
+     */
+    function process($callback, $mergeFiles = true)
+    {
+        if (!is_callable($callback)) {
+            return PEAR::raiseError(null, QUICKFORM_INVALID_PROCESS, null, E_USER_WARNING, "Callback function does not exist in QuickForm::process()", 'HTML_QuickForm_Error', true);
+        }
+        $values = ($mergeFiles === true) ? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles) : $this->_submitValues;
+        return call_user_func($callback, $values);
+    } // end func process
+
+    // }}}
+    // {{{ accept()
+
+   /**
+    * Accepts a renderer
+    *
+    * @param object     An HTML_QuickForm_Renderer object
+    * @since 3.0
+    * @access public
+    * @return void
+    */
+    function accept(&$renderer)
+    {
+        $renderer->startForm($this);
+        foreach (array_keys($this->_elements) as $key) {
+            $element =& $this->_elements[$key];
+            $elementName = $element->getName();
+            $required    = ($this->isElementRequired($elementName) && !$element->isFrozen());
+            $error       = $this->getElementError($elementName);
+            $element->accept($renderer, $required, $error);
+        }
+        $renderer->finishForm($this);
+    } // end func accept
+
+    // }}}
+    // {{{ defaultRenderer()
+
+   /**
+    * Returns a reference to default renderer object
+    *
+    * @access public
+    * @since 3.0
+    * @return object a default renderer object
+    */
+    function &defaultRenderer()
+    {
+        if (!isset($GLOBALS['_HTML_QuickForm_default_renderer'])) {
+            include_once('HTML/QuickForm/Renderer/Default.php');
+            $GLOBALS['_HTML_QuickForm_default_renderer'] = new HTML_QuickForm_Renderer_Default();
+        }
+        return $GLOBALS['_HTML_QuickForm_default_renderer'];
+    } // end func defaultRenderer
+
+    // }}}
+    // {{{ toHtml ()
+
+    /**
+     * Returns an HTML version of the form
+     *
+     * @param string $in_data (optional) Any extra data to insert right
+     *               before form is rendered.  Useful when using templates.
+     *
+     * @return   string     Html version of the form
+     * @since     1.0
+     * @access   public
+     */
+    function toHtml ($in_data = null)
+    {
+        if (!is_null($in_data)) {
+            $this->addElement('html', $in_data);
+        }
+        $renderer =& $this->defaultRenderer();
+        $this->accept($renderer);
+        return $renderer->toHtml();
+    } // end func toHtml
+
+    // }}}
+    // {{{ getValidationScript()
+
+    /**
+     * Returns the client side validation script
+     *
+     * @since     2.0
+     * @access    public
+     * @return    string    Javascript to perform validation, empty string if no 'client' rules were added
+     */
+    function getValidationScript()
+    {
+        if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) {
+            return '';
+        }
+
+        include_once('HTML/QuickForm/RuleRegistry.php');
+        $registry =& HTML_QuickForm_RuleRegistry::singleton();
+        $test = array();
+        $js_escape = array(
+            "\r"    => '\r',
+            "\n"    => '\n',
+            "\t"    => '\t',
+            "'"     => "\\'",
+            '"'     => '\"',
+            '\\'    => '\\\\'
+        );
+
+        foreach ($this->_rules as $elementName => $rules) {
+            foreach ($rules as $rule) {
+                if ('client' == $rule['validation']) {
+                    unset($element);
+
+                    $dependent  = isset($rule['dependent']) && is_array($rule['dependent']);
+                    $rule['message'] = strtr($rule['message'], $js_escape);
+
+                    if (isset($rule['group'])) {
+                        $group    =& $this->getElement($rule['group']);
+                        // No JavaScript validation for frozen elements
+                        if ($group->isFrozen()) {
+                            continue 2;
+                        }
+                        $elements =& $group->getElements();
+                        foreach (array_keys($elements) as $key) {
+                            if ($elementName == $group->getElementName($key)) {
+                                $element =& $elements[$key];
+                                break;
+                            }
+                        }
+                    } elseif ($dependent) {
+                        $element   =  array();
+                        $element[] =& $this->getElement($elementName);
+                        foreach ($rule['dependent'] as $elName) {
+                            $element[] =& $this->getElement($elName);
+                        }
+                    } else {
+                        $element =& $this->getElement($elementName);
+                    }
+                    // No JavaScript validation for frozen elements
+                    if (is_object($element) && $element->isFrozen()) {
+                        continue 2;
+                    } elseif (is_array($element)) {
+                        foreach (array_keys($element) as $key) {
+                            if ($element[$key]->isFrozen()) {
+                                continue 3;
+                            }
+                        }
+                    }
+
+                    $test[] = $registry->getValidationScript($element, $elementName, $rule);
+                }
+            }
+        }
+        if (count($test) > 0) {
+            return
+                "\n<script type=\"text/javascript\">\n" .
+                "//<![CDATA[\n" .
+                "function validate_" . $this->_attributes['id'] . "(frm) {\n" .
+                "  var value = '';\n" .
+                "  var errFlag = new Array();\n" .
+                "  var _qfGroups = {};\n" .
+                "  _qfMsg = '';\n\n" .
+                join("\n", $test) .
+                "\n  if (_qfMsg != '') {\n" .
+                "    _qfMsg = '" . strtr($this->_jsPrefix, $js_escape) . "' + _qfMsg;\n" .
+                "    _qfMsg = _qfMsg + '\\n" . strtr($this->_jsPostfix, $js_escape) . "';\n" .
+                "    alert(_qfMsg);\n" .
+                "    return false;\n" .
+                "  }\n" .
+                "  return true;\n" .
+                "}\n" .
+                "//]]>\n" .
+                "</script>";
+        }
+        return '';
+    } // end func getValidationScript
+
+    // }}}
+    // {{{ getSubmitValues()
+
+    /**
+     * Returns the values submitted by the form
+     *
+     * @since     2.0
+     * @access    public
+     * @param     bool      Whether uploaded files should be returned too
+     * @return    array
+     */
+    function getSubmitValues($mergeFiles = false)
+    {
+        return $mergeFiles? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles): $this->_submitValues;
+    } // end func getSubmitValues
+
+    // }}}
+    // {{{ toArray()
+
+    /**
+     * Returns the form's contents in an array.
+     *
+     * The description of the array structure is in HTML_QuickForm_Renderer_Array docs
+     *
+     * @since     2.0
+     * @access    public
+     * @param     bool      Whether to collect hidden elements (passed to the Renderer's constructor)
+     * @return    array of form contents
+     */
+    function toArray($collectHidden = false)
+    {
+        include_once 'HTML/QuickForm/Renderer/Array.php';
+        $renderer = new HTML_QuickForm_Renderer_Array($collectHidden);
+        $this->accept($renderer);
+        return $renderer->toArray();
+     } // end func toArray
+
+    // }}}
+    // {{{ exportValue()
+
+    /**
+     * Returns a 'safe' element's value
+     *
+     * This method first tries to find a cleaned-up submitted value,
+     * it will return a value set by setValue()/setDefaults()/setConstants()
+     * if submitted value does not exist for the given element.
+     *
+     * @param  string   Name of an element
+     * @access public
+     * @return mixed
+     * @throws HTML_QuickForm_Error
+     */
+    function exportValue($element)
+    {
+        if (!isset($this->_elementIndex[$element])) {
+            return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
+        }
+        $value = $this->_elements[$this->_elementIndex[$element]]->exportValue($this->_submitValues, false);
+        if (isset($this->_duplicateIndex[$element])) {
+            foreach ($this->_duplicateIndex[$element] as $index) {
+                if (null !== ($v = $this->_elements[$index]->exportValue($this->_submitValues, false))) {
+                    if (is_array($value)) {
+                        $value[] = $v;
+                    } else {
+                        $value = (null === $value)? $v: array($value, $v);
+                    }
+                }
+            }
+        }
+        return $value;
+    }
+
+    // }}}
+    // {{{ exportValues()
+
+    /**
+     * Returns 'safe' elements' values
+     *
+     * Unlike getSubmitValues(), this will return only the values
+     * corresponding to the elements present in the form.
+     *
+     * @param   mixed   Array/string of element names, whose values we want. If not set then return all elements.
+     * @access  public
+     * @return  array   An assoc array of elements' values
+     * @throws  HTML_QuickForm_Error
+     */
+    function exportValues($elementList = null)
+    {
+        $values = array();
+        if (null === $elementList) {
+            // iterate over all elements, calling their exportValue() methods
+            foreach (array_keys($this->_elements) as $key) {
+                $value = $this->_elements[$key]->exportValue($this->_submitValues, true);
+                if (is_array($value)) {
+                    // This shit throws a bogus warning in PHP 4.3.x
+                    $values = HTML_QuickForm::arrayMerge($values, $value);
+                }
+            }
+        } else {
+            if (!is_array($elementList)) {
+                $elementList = array_map('trim', explode(',', $elementList));
+            }
+            foreach ($elementList as $elementName) {
+                $value = $this->exportValue($elementName);
+                if (PEAR::isError($value)) {
+                    return $value;
+                }
+                $values[$elementName] = $value;
+            }
+        }
+        return $values;
+    }
+
+    // }}}
+    // {{{ isSubmitted()
+
+   /**
+    * Tells whether the form was already submitted
+    *
+    * This is useful since the _submitFiles and _submitValues arrays
+    * may be completely empty after the trackSubmit value is removed.
+    *
+    * @access public
+    * @return bool
+    */
+    function isSubmitted()
+    {
+        return $this->_flagSubmitted;
+    }
+
+
+    // }}}
+    // {{{ isError()
+
+    /**
+     * Tell whether a result from a QuickForm method is an error (an instance of HTML_QuickForm_Error)
+     *
+     * @access public
+     * @param mixed     result code
+     * @return bool     whether $value is an error
+     * @static
+     */
+    function isError($value)
+    {
+        return (is_object($value) && is_a($value, 'html_quickform_error'));
+    } // end func isError
+
+    // }}}
+    // {{{ errorMessage()
+
+    /**
+     * Return a textual error message for an QuickForm error code
+     *
+     * @access  public
+     * @param   int     error code
+     * @return  string  error message
+     * @static
+     */
+    function errorMessage($value)
+    {
+        // make the variable static so that it only has to do the defining on the first call
+        static $errorMessages;
+
+        // define the varies error messages
+        if (!isset($errorMessages)) {
+            $errorMessages = array(
+                QUICKFORM_OK                    => 'no error',
+                QUICKFORM_ERROR                 => 'unknown error',
+                QUICKFORM_INVALID_RULE          => 'the rule does not exist as a registered rule',
+                QUICKFORM_NONEXIST_ELEMENT      => 'nonexistent html element',
+                QUICKFORM_INVALID_FILTER        => 'invalid filter',
+                QUICKFORM_UNREGISTERED_ELEMENT  => 'unregistered element',
+                QUICKFORM_INVALID_ELEMENT_NAME  => 'element already exists',
+                QUICKFORM_INVALID_PROCESS       => 'process callback does not exist',
+                QUICKFORM_DEPRECATED            => 'method is deprecated',
+                QUICKFORM_INVALID_DATASOURCE    => 'datasource is not an object'
+            );
+        }
+
+        // If this is an error object, then grab the corresponding error code
+        if (HTML_QuickForm::isError($value)) {
+            $value = $value->getCode();
+        }
+
+        // return the textual error message corresponding to the code
+        return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[QUICKFORM_ERROR];
+    } // end func errorMessage
+
+    // }}}
+} // end class HTML_QuickForm
+
+/**
+ * Class for errors thrown by HTML_QuickForm package
+ *
+ * @category    HTML
+ * @package     HTML_QuickForm
+ * @author      Adam Daniel <adaniel1@eesus.jnj.com>
+ * @author      Bertrand Mansion <bmansion@mamasam.com>
+ * @version     Release: 3.2.16
+ */
+class HTML_QuickForm_Error extends PEAR_Error {
+
+    // {{{ properties
+
+    /**
+    * Prefix for all error messages
+    * @var string
+    */
+    var $error_message_prefix = 'QuickForm Error: ';
+
+    // }}}
+    // {{{ constructor
+
+    /**
+    * Creates a quickform error object, extending the PEAR_Error class
+    *
+    * @param int   $code the error code
+    * @param int   $mode the reaction to the error, either return, die or trigger/callback
+    * @param int   $level intensity of the error (PHP error code)
+    * @param mixed $debuginfo any information that can inform user as to nature of the error
+    */
+    function HTML_QuickForm_Error($code = QUICKFORM_ERROR, $mode = PEAR_ERROR_RETURN,
+                         $level = E_USER_NOTICE, $debuginfo = null)
+    {
+        if (is_int($code)) {
+            $this->PEAR_Error(HTML_QuickForm::errorMessage($code), $code, $mode, $level, $debuginfo);
+        } else {
+            $this->PEAR_Error("Invalid error code: $code", QUICKFORM_ERROR, $mode, $level, $debuginfo);
+        }
+    }
+
+    // }}}
+} // end class HTML_QuickForm_Error
+?>