<?php /*

 Composr
 Copyright (c) ocProducts, 2004-2016

 See text/EN/licence.txt for full licencing information.


 NOTE TO PROGRAMMERS:
   Do not edit this file. If you need to make changes, save your changed file to the appropriate *_custom folder
   **** If you ignore this advice, then your website upgrades (e.g. for bug fixes) will likely kill your changes ****

*/

/**
 * @license    http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
 * @copyright  ocProducts Ltd
 * @package    core
 */

/*EXTRA FUNCTIONS: memory_get_usage|memory_get_peak_usage*/

/**
 * Standard code module initialisation function.
 *
 * @ignore
 */
function init__symbols()
{
    global $BLOCKS_CACHE, $PAGES_CACHE, $PANELS_CACHE, $EXTRA_SYMBOLS, $PREPROCESSABLE_SYMBOLS, $CANONICAL_URL, $STATIC_TEMPLATE_TEST_MODE, $SYMBOLS2_CAUSE;
    $BLOCKS_CACHE = array();
    $PAGES_CACHE = array();
    $PANELS_CACHE = array();
    $PREPROCESSABLE_SYMBOLS = array(
        'PAGE_LINK' => true,
        'SET' => true,
        'BLOCK' => true,
        'FACILITATE_AJAX_BLOCK_CALL' => true,
        'REQUIRE_JAVASCRIPT' => true,
        'REQUIRE_CSS' => true,
        'LOAD_PANEL' => true,
        'JS_TEMPCODE' => true,
        'CSS_TEMPCODE' => true,
        'LOAD_PAGE' => true,
        'FRACTIONAL_EDITABLE' => true,
        'PAGE_TITLE' => true,
    );
    $EXTRA_SYMBOLS = null;
    $CANONICAL_URL = null;
    $STATIC_TEMPLATE_TEST_MODE = false;
    $SYMBOLS2_CAUSE = array();
}

/**
 * Evaluate a conventional Tempcode construct, handling escaping
 *
 * @param  string $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  integer $type The type of symbol this is (TC_SYMBOL, TC_LANGUAGE_REFERENCE)
 * @set    0 2
 * @param  ID_TEXT $name The name of the symbol
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return mixed The result. Either Tempcode, or a string.
 */
function ecv($lang, $escaped, $type, $name, $param)
{
    $name = trim($name);

    // SYMBOLS...
    if ($type === TC_SYMBOL) {
        // Built-in
        if ($name === '?') {
            $value = call_user_func('ecv_TERNARY', $lang, $escaped, $param);
        } elseif (function_exists('ecv_' . $name)) {
            $value = call_user_func('ecv_' . $name, $lang, $escaped, $param);
        } else {
            // Maybe a hook?
            global $EXTRA_SYMBOLS;
            if ($EXTRA_SYMBOLS === null) {
                if (running_script('install')) {
                    $EXTRA_SYMBOLS = array('BETA_CSS_PROPERTY' => array()); // Needed for installer to look good ('find_all_hooks' won't run in initial steps of quick installer)
                } else {
                    $EXTRA_SYMBOLS = array();
                    $hooks = find_all_hooks('systems', 'symbols');
                    foreach (array_keys($hooks) as $hook) {
                        $EXTRA_SYMBOLS[$hook] = array();
                    }
                }
            }
            if (isset($EXTRA_SYMBOLS[$name])) {
                if (!isset($EXTRA_SYMBOLS[$name]['ob'])) {
                    require_code('hooks/systems/symbols/' . filter_naughty_harsh($name, true));
                    $EXTRA_SYMBOLS[$name]['ob'] = object_factory('Hook_symbol_' . filter_naughty_harsh($name, true));
                }
                $value = $EXTRA_SYMBOLS[$name]['ob']->run($param);

                if ($escaped !== array()) {
                    if (is_object($value)) {
                        $value = $value->evaluate();
                    }
                    apply_tempcode_escaping($escaped, $value);
                }
            } else {
                // A less common symbol?
                if (defined($name)) {
                    $value = @strval(constant($name));
                    if (!is_string($value)) {
                        $value = strval($value);
                    }

                    if ($escaped !== array()) {
                        if (is_object($value)) {
                            $value = $value->evaluate();
                        }
                        apply_tempcode_escaping($escaped, $value);
                    }
                } else {
                    require_code('symbols2');
                    if (function_exists('ecv2_' . $name)) {
                        global $SYMBOLS2_CAUSE;
                        $SYMBOLS2_CAUSE[] = $name;

                        $value = call_user_func('ecv2_' . $name, $lang, $escaped, $param); // A constant?
                    }
                    // Error :-(
                    else {
                        $value = '';
                        if ($GLOBALS['XSS_DETECT']) {
                            ocp_mark_as_escaped($value);
                        }
                        if (!running_script('install')) {
                            require_code('site');
                            attach_message(do_lang_tempcode('MISSING_SYMBOL', escape_html($name)), 'warn');

                            persistent_cache_delete('HOOKS'); // May be a cache issue, find it on refresh
                        }
                    }
                }
            }
        }

        return $value;
    }

    // DIRECTIVES...

    if ($type === TC_DIRECTIVE) {
        $value = '';
        if ($GLOBALS['XSS_DETECT']) {
            ocp_mark_as_escaped($value);
        }

        // In our param we should have a map of bubbled template parameters (under 'vars') and our numbered directive parameters

        if ($param === null) {
            $param = array();
        }

        // Closure-based Tempcode parser may send in strings, so we need to adapt...
        foreach ($param as $key => $val) {
            if (is_string($val)) {
                $param[$key] = make_string_tempcode($val);
            }
        }

        if (!isset($param['vars'])) {
            $param['vars'] = array();
        }

        switch ($name) {
            case 'IF':
                require_code('symbols2');
                ecv2_IF($value, $lang, $escaped, $param);
                break;

            case 'IF_EMPTY':
                require_code('symbols2');
                ecv2_IF_EMPTY($value, $lang, $escaped, $param);
                break;

            case 'IF_NON_EMPTY':
                require_code('symbols2');
                ecv2_IF_NON_EMPTY($value, $lang, $escaped, $param);
                break;

            case 'IF_PASSED':
                require_code('symbols2');
                ecv2_IF_PASSED($value, $lang, $escaped, $param);
                break;

            case 'IF_NON_PASSED':
                require_code('symbols2');
                ecv2_IF_NON_PASSED($value, $lang, $escaped, $param);
                break;

            case 'IF_PASSED_AND_TRUE':
                require_code('symbols2');
                ecv2_IF_PASSED_AND_TRUE($value, $lang, $escaped, $param);
                break;

            case 'IF_NON_PASSED_OR_FALSE':
                require_code('symbols2');
                ecv2_IF_NON_PASSED_OR_FALSE($value, $lang, $escaped, $param);
                break;

            case 'WHILE':
                require_code('symbols2');
                ecv2_WHILE($value, $lang, $escaped, $param);
                break;

            case 'LOOP':
                require_code('symbols2');
                ecv2_LOOP($value, $lang, $escaped, $param);
                break;

            case 'PARAM_INFO':
                $_value = do_template('PARAM_INFO', array('_GUID' => '960e11880fbc512a3170756ca43384fd', 'MAP' => $param['vars']));
                $value = $_value->evaluate();
                break;

            case 'CSS_INHERIT':
                require_code('symbols2');
                ecv2_CSS_INHERIT($value, $lang, $escaped, $param);
                break;

            case 'FRACTIONAL_EDITABLE':
                require_javascript('ajax');
                require_javascript('fractional_edit');

                foreach (array_keys($param) as $key) {
                    if (!is_numeric($key)) {
                        unset($param[$key]);
                    }
                }
                if (isset($param[3])) {
                    $edit_text = $param[0]->evaluate();
                    $edit_param_name = $param[1]->evaluate();
                    $edit_page_link = $param[2]->evaluate();
                    $supports_comcode = (isset($param[4]) ? $param[3]->evaluate() : '0') === '1';
                    $explicit_editing_links = (isset($param[5]) ? $param[4]->evaluate() : '0') === '1';
                    $has_permission = (isset($param[6]) ? ($param[5]->evaluate() === '1') : null);

                    list($zone, $attributes,) = page_link_decode($edit_page_link);
                    if ($zone === '_SEARCH') {
                        $zone = get_module_zone($attributes['page']);
                    }
                    if (
                        (get_option('fractional_editing') == '1') &&
                        (has_actual_page_access(get_member(), $attributes['page'], $zone)) &&
                        (($has_permission === true) || (($has_permission === null) && (has_zone_access(get_member(), 'adminzone'))))
                    ) {
                        $keep = symbol_tempcode('KEEP');
                        $url = find_script('fractional_edit') . '?edit_param_name=' . urlencode($edit_param_name) . '&supports_comcode=' . ($supports_comcode ? '1' : '0') . '&zone=' . urlencode($zone) . $keep->evaluate();
                        if (count($attributes) > 0) {
                            $url .= '&' . http_build_query($attributes);
                        }

                        $_value = $param[count($param) - 1];
                        $_value = do_template('FRACTIONAL_EDIT', array(
                            '_GUID' => '075ac126c427d28b309004bc67b32b08',
                            'VALUE' => $_value,
                            'URL' => $url,
                            'EDIT_TEXT' => $edit_text,
                            'EDIT_PARAM_NAME' => $edit_param_name,
                            'EXPLICIT_EDITING_LINKS' => $explicit_editing_links,
                        ));
                        $value = $_value->evaluate();
                    } else {
                        $value = $param[count($param) - 1]->evaluate();
                    }
                }
                break;

            case 'SET':
                if (isset($param[1])) {
                    unset($param['vars']);
                    global $TEMPCODE_SETGET;
                    if (count($param) == 2) {
                        $TEMPCODE_SETGET[isset($param[0]->codename/*faster than is_object*/) ? $param[0]->evaluate() : $param[0]] = $param[1];
                    } else {
                        $param_copy = array();
                        foreach ($param as $i => $x) {
                            if ($i !== 0) {
                                $param_copy[] = isset($x->codename/*faster than is_object*/) ? $x->evaluate() : $x;
                            }
                        }
                        $TEMPCODE_SETGET[isset($param[0]->codename/*faster than is_object*/) ? $param[0]->evaluate() : $param[0]] = implode(',', $param_copy);
                    }
                }
                break;

            case 'IMPLODE':
                if (isset($param[1])) {
                    $key = $param[1]->evaluate();
                    $array = array_key_exists($key, $param['vars']) ? $param['vars'][$key] : array();
                    if ((isset($param[2])) && ($param[2]->evaluate() == '1')) {
                        $delim = $param[0]->evaluate();
                        foreach ($array as $key => $val) {
                            if ($value != '') {
                                $value .= $delim;
                            }
                            $value .= escape_html((is_integer($key) ? integer_format($key) : $key) . '=' . $val);
                        }
                    } else {
                        foreach ($array as &$key) {
                            if ((isset($param[3])) && ($param[3]->evaluate() == '1')) {
                                $key = escape_html($key);
                            }
                        }
                        $value = implode($param[0]->evaluate(), $array);
                    }
                }
                break;

            case 'COUNT':
                if (isset($param[0])) {
                    $key = $param[0]->evaluate();
                    $array = array_key_exists($key, $param['vars']) ? $param['vars'][$key] : array();
                    if (is_array($array)) {
                        $value = strval(count($array));
                    }
                }
                break;

            case 'BOX':
                unset($param['vars']);
                $title = isset($param[1]) ? $param[0]->evaluate() : '';
                $box_type = isset($param[2]) ? $param[1]->evaluate() : '';
                $width = isset($param[3]) ? $param[2]->evaluate() : '';
                $options = isset($param[4]) ? $param[3]->evaluate() : '';
                $meta = isset($param[5]) ? $param[4]->evaluate() : '';
                $links = isset($param[6]) ? $param[5]->evaluate() : '';
                $top_links = isset($param[7]) ? $param[6]->evaluate() : '';
                $class = isset($param[8]) ? $param[7]->evaluate() : '';
                $tmp = put_in_standard_box(array_pop($param), $title, $box_type, $width, $options, $meta, $links, $top_links, $class);
                $value = $tmp->evaluate();
                break;

            case 'NO_PREPROCESSING':
                $value = $param[0]->evaluate();
                break;

            case 'OF':
                if (isset($param[1])) {
                    $key = $param[0]->evaluate();
                    $x = $param[1]->evaluate();

                    $array = array_key_exists($key, $param['vars']) ? $param['vars'][$key] : array();
                    if (is_array($array)) {
                        $x2 = is_numeric($x) ? intval($x) : $x;
                        if (is_integer($x2)) {
                            if ($x2 < 0) {
                                $x2 = count($array) - 1;
                            } elseif ($x2 >= count($array)) {
                                $x2 -= count($array);
                            }
                        }
                        $value = array_key_exists($x2, $array) ? $array[$x2] : '';
                        if (is_object($value)) {
                            $value = $value->evaluate();
                        }
                    }
                }
                break;

            case 'RECONTEXTUALISE_IDS':
                require_code('symbols2');
                ecv2_RECONTEXTUALISE_IDS($value, $lang, $escaped, $param);
                break;

            case 'INCLUDE':
                if (isset($param[1])) {
                    $tpl_params = $param['vars'];
                    $var_data = $param[count($param) - 2]->evaluate();
                    $explode = explode("\n", $var_data);
                    foreach ($explode as $val) {
                        $bits = explode('=', $val, 2);
                        if (count($bits) == 2) {
                            $save_as = ltrim($bits[0]);
                            $tpl_params[$save_as] = str_replace('\n', "\n", $bits[1]);

                            if ($GLOBALS['XSS_DETECT'] && ocp_is_escaped($var_data)) {
                                ocp_mark_as_escaped($tpl_params[$save_as]);
                            }
                        }
                    }
                    $ex = isset($param[2]) ? $param[1]->evaluate() : '';
                    if ($ex == '') {
                        $ex = '.tpl';
                    }
                    $td = isset($param[3]) ? $param[2]->evaluate() : '';
                    if ($td == '') {
                        $td = 'templates';
                    }
                    $theme = isset($param[4]) ? $param[3]->evaluate() : '';
                    if ($theme == '') {
                        $theme = null;
                    }
                    $_value = do_template($param[0]->evaluate(), $tpl_params, null, true, null, $ex, $td, $theme);
                    $value = $_value->evaluate();

                    if ((get_charset() == 'utf-8') && (substr($value, 0, 3) == chr(hexdec('EF')) . chr(hexdec('BB')) . chr(hexdec('BF')))) {
                        $value = substr($value, 3);
                    }
                }
                break;

            case 'IF_IN_ARRAY':
                if (isset($param[2])) {
                    $key = $param[0]->evaluate();
                    $array = array_key_exists($key, $param['vars']) ? $param['vars'][$key] : array();
                    $value = '';
                    if ($GLOBALS['XSS_DETECT']) {
                        ocp_mark_as_escaped($value);
                    }
                    $i = 1;
                    while (isset($param[$i + 1])) {
                        $checking_in = $param[$i]->evaluate();
                        if (in_array($checking_in, $array)) {
                            $value = $param[count($param) - 2]->evaluate();
                            break;
                        }
                        $i++;
                    }
                }
                break;

            case 'IF_NOT_IN_ARRAY':
                if (isset($param[2])) {
                    $key = $param[0]->evaluate();
                    $array = array_key_exists($key, $param['vars']) ? $param['vars'][$key] : array();
                    $value = '';
                    if ($GLOBALS['XSS_DETECT']) {
                        ocp_mark_as_escaped($value);
                    }
                    $ok = true;
                    $i = 1;
                    while (isset($param[$i + 1])) {
                        $checking_in = $param[$i]->evaluate();
                        if (in_array($checking_in, $array)) {
                            $ok = false;
                            break;
                        }
                        $i++;
                    }
                    if ($ok) {
                        $value = $param[$i]->evaluate();
                    }
                }
                break;

            case 'IF_ARRAY_EMPTY':
                if (isset($param[0])) {
                    $looking_at = $param[0]->evaluate();
                    if (array_key_exists($looking_at, $param['vars'])) {
                        if ((is_array($param['vars'][$looking_at])) && (count($param['vars'][$looking_at]) == 0)) {
                            $value = $param[1]->evaluate();
                        }
                    }
                }
                break;

            case 'IF_ARRAY_NON_EMPTY':
                if (isset($param[0])) {
                    $looking_at = $param[0]->evaluate();
                    if (array_key_exists($looking_at, $param['vars'])) {
                        if ((is_array($param['vars'][$looking_at])) && (count($param['vars'][$looking_at]) != 0)) {
                            $value = $param[1]->evaluate();
                        }
                    }
                }
                break;

            case 'COMMENT':
                break;

            case 'CASES':
                if (isset($param[1])) {
                    $value = '';
                    $compare = $param[0]->evaluate();
                    $substring = (isset($param[2]) && $param[1]->evaluate() == '1');
                    $regexp = (isset($param[2]) && $param[1]->evaluate() == '2');
                    $explode = explode(chr(10), trim($param[isset($param[2]) ? 2 : 1]->evaluate()));
                    foreach ($explode as $i => $case) {
                        if (strpos($case, '=') === false) {
                            continue;
                        }
                        list($compare_case, $value_case) = explode('=', $case, 2);
                        $compare_case = trim($compare_case);
                        if (
                            ((!$substring) && (!$regexp) && ($compare_case == $compare)) || // Exact match
                            (($substring) && (($compare_case == '') || (strpos($compare, $compare_case) !== false))) || // Substring
                            (($regexp) && (preg_match('#' . str_replace('#', '\#', $compare_case) . '#', $compare) != 0)) || // Regexp
                            (($compare_case == '') && (!isset($explode[$i + 1]))) // The final default case
                        ) {
                            $value = $value_case;
                            break;
                        }
                    }
                }
                break;

            default:
                require_code('site');
                attach_message(do_lang_tempcode('UNKNOWN_DIRECTIVE', escape_html($name)), 'warn');
        }

        if ($escaped !== array()) {
            apply_tempcode_escaping($escaped, $value);
        }

        return $value;
    }

    // LANGUAGE STRINGS...

    $a = isset($param[0]) ? (is_object($param[0]) ? $param[0]->evaluate() : $param[0]) : null;
    $b = isset($param[1]) ? (is_object($param[1]) ? $param[1]->evaluate() : $param[1]) : null;
    $c = isset($param[2]) ? array_splice($param, 2) : null;
    if ($c !== null) {
        foreach ($c as $i => $cc) {
            if (is_object($cc)) {
                $c[$i] = $cc->evaluate();
            }
        }
    }
    static $dle = false;
    if (!$dle) {
        $dle = function_exists('do_lang');
    }
    $value = $dle ? do_lang($name, $a, $b, $c, $lang, false) : escape_html($name . ':' . (($a !== null) ? $a : '') . ',' . (($b !== null) ? $b : ''));
    if ($value === null) {
        require_code('site');
        attach_message(do_lang_tempcode('MISSING_LANG_STRING', escape_html($name)), 'warn');

        $value = '';
        if ($GLOBALS['XSS_DETECT']) {
            ocp_mark_as_escaped($value);
        }
        return $value;
    }
    if ($escaped !== array() && $escaped !== array(ENTITY_ESCAPED)) {
        apply_tempcode_escaping(array_diff($escaped, array(ENTITY_ESCAPED)), $value); // Escape but without ENTITY_ESCAPED because we don't do that on language strings
    } elseif ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_PAGE_LINK($lang, $escaped, $param)
{
    if (isset($param[0])) {
        list($zone, $map, $hash) = page_link_decode(isset($param[0]->codename)/*faster than is_object*/ ? $param[0]->evaluate() : $param[0]);

        $skip = null;

        if (isset($param[1])) {
            $avoid_remap = ($param[1] == '1');
            $skip_keep = isset($param[2]) && ($param[2] == '1');
            $keep_all = isset($param[3]) && ($param[3] == '1');
            if (isset($param[4])) {
                $skip = array_flip(explode('|', $param[4]));
            }
        } else {
            $avoid_remap = false;
            $skip_keep = false;
            $keep_all = false;
        }

        $value = _build_url($map, $zone, $skip, $keep_all, $avoid_remap, $skip_keep, $hash);
    } else {
        $value = get_zone_name() . ':' . get_page_name();
        foreach ($_GET as $key => $val) {
            if ($key == 'page') {
                continue;
            }
            if (is_array($val)) {
                continue;
            }
            if ((substr($key, 0, 5) == 'keep_') && (!skippable_keep($key, $val))) {
                continue;
            }
            $value .= ':' . $key . '=' . $val;
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_SET($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    global $TEMPCODE_SETGET;

    if (isset($param[1])) {
        if ((count($param) == 2) || (isset($param[1]) && isset($param[1]->codename)/*faster than is_object*/)) {
            $TEMPCODE_SETGET[$param[0]] = $param[1];
        } else {
            $param_copy = $param;
            unset($param_copy[0]);
            $TEMPCODE_SETGET[$param[0]] = isset($param_copy[2]/*optimisation*/) ? implode(',', $param_copy) : $param_copy[1];
        }
    } else {
        $TEMPCODE_SETGET[$param[0]] = '';
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_GET($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        global $TEMPCODE_SETGET;
        if (isset($TEMPCODE_SETGET[$param[0]])) {
            if (isset($TEMPCODE_SETGET[$param[0]]->codename)/*faster than is_object*/) {
                if ((array_key_exists(1, $param)) && (((is_string($param[1])) && ($param[1] == '1')) || ((is_object($param[1])) && ($param[1]->evaluate() == '1')))) { // no-cache
                    $TEMPCODE_SETGET[$param[0]]->decache();
                    $value = $TEMPCODE_SETGET[$param[0]]->evaluate();
                    $TEMPCODE_SETGET[$param[0]]->decache();

                    if ((!has_solemnly_declared(I_UNDERSTAND_XSS)) && ($escaped === array())) {
                        $escaped = array(ENTITY_ESCAPED);
                    }

                    if ($escaped !== array()) {
                        apply_tempcode_escaping($escaped, $value);
                    }
                    return $value;
                }

                $TEMPCODE_SETGET[$param[0]] = $TEMPCODE_SETGET[$param[0]]->evaluate();
            }

            $value = $TEMPCODE_SETGET[$param[0]];
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HAS_ACTUAL_PAGE_ACCESS($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        $value = has_actual_page_access(((isset($param[2]))) ? intval($param[2]) : get_member(), $param[0], isset($param[1]) ? $param[1] : null) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_TERNARY($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[1])) {
        $value = ($param[0] == '1') ? $param[1] : (isset($param[2]) ? $param[2] : $value);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IMG($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        if ((isset($GLOBALS['SITE_DB'])) && (function_exists('find_theme_image')) && (!$GLOBALS['IN_MINIKERNEL_VERSION']) && ($GLOBALS['FORUM_DRIVER'] !== null)) {
            $value = find_theme_image($param[0], ((isset($param[3])) && ($param[3] === '1')), false, (isset($param[2]) && $param[2] !== '') ? $param[2] : null, null, ((isset($param[1])) && ($param[1] === '1')) ? $GLOBALS['FORUM_DB'] : $GLOBALS['SITE_DB']);
        } else {
            $value = 'themes/default/images/' . $param[0] . '.png';
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IMG_MTIME($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        $path = find_theme_image($param[0], true, true);
        if ($path != '') {
            $full_path = get_custom_file_base() . '/' . $path;
            if (!is_file($full_path)) {
                $full_path = get_file_base() . '/' . $path;
            }
            $value = @strval(filemtime($full_path));
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IMG_WIDTH($lang, $escaped, $param)
{
    require_code('images');
    list($value,) = _symbol_image_dims($param);

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IMG_HEIGHT($lang, $escaped, $param)
{
    require_code('images');
    list(, $value) = _symbol_image_dims($param);

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_($lang, $escaped, $param) // A Tempcode comment
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_REFRESH($lang, $escaped, $param)
{
    // Is this refreshing?
    global $REFRESH_URL, $FORCE_META_REFRESH;
    if ((!running_script('upgrader')) && (get_option('force_meta_refresh') == '1')) {
        $FORCE_META_REFRESH = true;
    }
    if ((array_key_exists(0, $REFRESH_URL)) && ($REFRESH_URL[0] != '') && ($FORCE_META_REFRESH)) { // The page itself has actually told it to refresh itself DISABLED FOR ACCESSIBILITY REASONS: Now headers do refreshing when it's crucial
        if (!array_key_exists(1, $REFRESH_URL)) {
            $REFRESH_URL[1] = 1;
        }
        $refresh = do_template('META_REFRESH_LINE', array('_GUID' => '6ee20694dfa474f160481a3ab5331d87', 'URL' => $REFRESH_URL[0], 'TIME' => integer_format($REFRESH_URL[1])));
    } else {
        $refresh = new Tempcode();
    }
    $value = $refresh->evaluate();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_FEEDS($lang, $escaped, $param)
{
    // Feeds
    if ((get_option('is_on_rss', true) === '1') && (addon_installed('syndication'))) {
        $feeds = new Tempcode();
        if (addon_installed('news')) {
            $feeds->attach(do_template('RSS_HEADER', array('_GUID' => '53e135b04502d6df64f1570b61310f30', 'FEED_URL' => find_script('backend') . '?mode=news', 'TITLE' => do_lang('NEWS'))));
        }
        if ($GLOBALS['FEED_URL'] !== null) {
            if (substr($GLOBALS['FEED_URL'], 0, 1) == '?') {
                $GLOBALS['FEED_URL'] = find_script('backend') . $GLOBALS['FEED_URL'];
            }
            $feeds->attach(do_template('RSS_HEADER', array('_GUID' => '3a289a821e87e954494753edf7cb2ebd', 'FEED_URL' => $GLOBALS['FEED_URL'])));
        }
        if ($GLOBALS['FEED_URL_2'] !== null) {
            if (substr($GLOBALS['FEED_URL_2'], 0, 1) == '?') {
                $GLOBALS['FEED_URL_2'] = find_script('backend') . $GLOBALS['FEED_URL_2'];
            }
            $feeds->attach(do_template('RSS_HEADER', array('_GUID' => 'fa8c7aaa3601c24d1986fa2598416558', 'FEED_URL' => $GLOBALS['FEED_URL_2'], 'TITLE' => do_lang('COMMENTS'))));
        }
        $value = $feeds->evaluate();
    } else {
        $value = '';
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_METADATA($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        global $METADATA, $BREADCRUMB_SET_SELF;

        switch ($param[0]) {
            case 'site_newestmember':
                $value = get_value('cns_newest_member_username');
                if (is_null($value)) {
                    $value = '';
                }
                break;
            case 'site_nummembers':
                if (!is_null($GLOBALS['FORUM_DRIVER'])) {
                    $value = strval($GLOBALS['FORUM_DRIVER']->get_members());
                }
                break;
            case 'site_bestmember':
                $value = get_value('site_bestmember');
                if (is_null($value)) {
                    $value = '';
                }
                break;
            case 'forum_numtopics':
                if (!is_null($GLOBALS['FORUM_DRIVER'])) {
                    $value = strval($GLOBALS['FORUM_DRIVER']->get_topics());
                }
                break;
            case 'forum_numposts':
                if (!is_null($GLOBALS['FORUM_DRIVER'])) {
                    $value = strval($GLOBALS['FORUM_DRIVER']->get_num_forum_posts());
                }
                break;

            case 'meta_description':
                if (isset($param[2])) {
                    list(, $value) = seo_meta_get_for($param[1], $param[2]);
                } else {
                    global $SEO_DESCRIPTION;
                    if (($SEO_DESCRIPTION === null) || ($SEO_DESCRIPTION == '')) {
                        if (!empty($METADATA['description'])) {
                            $value = strip_comcode($METADATA['description']);
                        } else {
                            $value = get_option('description');
                        }
                    } else {
                        $value = $SEO_DESCRIPTION;
                    }
                }
                break;

            case 'raw_keywords':
                global $SEO_KEYWORDS;
                if ($SEO_KEYWORDS === null) {
                    $SEO_KEYWORDS = array();
                }
                $keywords_array = $SEO_KEYWORDS;
                $value = implode(',', array_unique($keywords_array));
                break;

            case 'keywords':
                if (isset($param[2])) {
                    list($value,) = seo_meta_get_for($param[1], $param[2]);
                } else {
                    global $SEO_KEYWORDS;
                    $keywords = get_option('keywords');
                    if ($SEO_KEYWORDS === null) {
                        $SEO_KEYWORDS = array();
                    }
                    $keywords_array = $SEO_KEYWORDS;
                    if ($keywords != '') {
                        $keywords_array = array_merge($keywords_array, array_map('trim', explode(',', $keywords)));
                    }
                    $value = implode(',', array_unique($keywords_array));
                }
                break;

            default:
                if (isset($param[1])) {
                    switch ($param[0]) {
                        case 'breadcrumb_self':
                            $BREADCRUMB_SET_SELF = $param[1];
                            break;

                        default:
                            $matches = array();
                            // If attachment given, check permissions
                            if (($param[0] == 'image') && (preg_match('#^' . preg_quote(find_script('attachment'), '#') . '\?id=(\d+)#', $param[1], $matches) != 0)) {
                                require_code('attachments');
                                if (!has_attachment_access($GLOBALS['FORUM_DRIVER']->get_guest_id(), intval($matches[1]))) {
                                    break;
                                }
                            }

                            $METADATA[$param[0]] = $param[1];
                            break;
                    }
                } else {
                    if (isset($METADATA[$param[0]])) {
                        $value = $METADATA[$param[0]];
                        if ($param[0] != 'image') {
                            $value = $METADATA[$param[0]];
                            if ($param[0] == 'title' || $param[0] == 'description') {
                                $value = strip_comcode($value);
                            }
                        }
                    } else {
                        $value = '';
                    }
                    if ($value === null) {
                        $value = '';
                    }
                }
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_KEEP($lang, $escaped, $param)
{
    // What needs preserving in the URL
    $value = keep_symbol($param);

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * String to tack onto URL to keep 'keep_' parameters.
 *
 * @param  array $param Parameters passed to the symbol (0=whether this starts off the query string, 1=force session append even if it's also available a session cookie e.g. when put into download manager)
 * @return string The result.
 */
function keep_symbol($param)
{
    $value = '';
    $get_vars = $_GET;
    if ((isset($param[1])) && ($param[1] === '1') && (is_null(get_bot_type())) && (!isset($get_vars['keep_session']))) {
        $get_vars['keep_session'] = get_session_id();
    }

    static $gpc = null;
    if ($gpc === null) {
        $gpc = @get_magic_quotes_gpc();
    }

    $first = ((isset($param[0])) && ($param[0] === '1'));
    foreach ($get_vars as $key => $val) {
        if (($gpc) && (is_string($val))) {
            $val = stripslashes($val);
        }

        if ((@$key[0] == 'k') && (substr($key, 0, 5) === 'keep_') && ((!skippable_keep($key, $val)) || (($key === 'keep_session') && (is_null(get_bot_type())) && (isset($param[1])) && ($param[1] === '1'))) && (is_string($val))) {
            $value .= ($first ? '?' : '&') . urlencode($key) . '=' . cms_url_encode($val);
            $first = false;
        }
    }

    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_BROWSER($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        $q = false;
        foreach (explode('|', $param[0]) as $browser) {
            $q = browser_matches($browser);
            if ($q) {
                break;
            }
        }
        $value = $q ? $param[1] : (isset($param[2]) ? $param[2] : '');
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_REQUIRE_JAVASCRIPT($lang, $escaped, $param)
{
    if (isset($param[0])) {
        global $JAVASCRIPTS;
        if (!isset($JAVASCRIPTS[$param[0]])) {
            if ((isset($param[1])) && ($param[1] == '1')) {
                global $JAVASCRIPT_BOTTOM;
                $JAVASCRIPT_BOTTOM[$param[0]] = true;
            }

            require_javascript($param[0]);
            /*// Has to do this inline, as you're "hidden" id="include_sitemap allowed to reference scripts outside head
            if (!array_key_exists($param[0], $GLOBALS['JAVASCRIPTS'])) {
                    $GLOBALS['JAVASCRIPTS'][$param[0]] = true;
                    $file = javascript_enforce($param[0]);
                    $_value = do_template('JAVASCRIPT_NEED_INLINE', array('_GUID' => 'd6c907e26c5a8dd8c65f1d36a1a674a9', 'CODE' => file_get_contents($file)));
                    $value = $_value->evaluate();
            }*/
        }
    }

    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_FACILITATE_AJAX_BLOCK_CALL($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        require_javascript('ajax');

        require_code('blocks');
        $_block_constraints = block_params_to_block_signature(block_params_str_to_arr($param[0]));
        if (isset($param[1])) {
            $_block_constraints = array_merge($_block_constraints, block_params_str_to_arr($param[1]));
            ksort($_block_constraints);
        }
        $block_constraints = block_params_arr_to_str($_block_constraints);

        // Store permissions
        $_auth_key = $GLOBALS['SITE_DB']->query_select('temp_block_permissions', array('id', 'p_time'), array(
            'p_session_id' => get_session_id(),
            'p_block_constraints' => $block_constraints,
        ), '', 1);
        if (!isset($_auth_key[0])) {
            $auth_key = $GLOBALS['SITE_DB']->query_insert('temp_block_permissions', array(
                'p_session_id' => get_session_id(),
                'p_block_constraints' => $block_constraints,
                'p_time' => time(),
            ), true);
        } else {
            $auth_key = $_auth_key[0]['id'];
            if (time() - $_auth_key[0]['p_time'] > 100) {
                $GLOBALS['SITE_DB']->query_update('temp_block_permissions', array('p_time' => time()), array(
                    'p_session_id' => get_session_id(),
                    'p_block_constraints' => $block_constraints,
                ), '', 1);
            }
        }

        $keep = symbol_tempcode('KEEP');
        $value = find_script('snippet') . '?snippet=block&auth_key=' . urlencode(strval($auth_key)) . '&block_map=' . urlencode($param[0]) . $keep->evaluate();
        if (get_param_string('keep_theme', null) !== null) {
            $value .= '&keep_theme=' . urlencode($GLOBALS['FORUM_DRIVER']->get_theme());
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv__GET($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $value = get_param_string($param[0], isset($param[1]) ? $param[1] : '', true);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_STRIP_TAGS($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        if ((isset($param[1])) && ($param[1] == '1')) {
            $value = strip_tags(str_replace('))', ')', str_replace('((', '(', str_replace('<em>', '(', str_replace('</em>', ')', $param[0])))));
        } else {
            if (strpos($param[0], '<') === false) { // optimisation
                $value = $param[0];
            } else {
                $value = strip_tags($param[0], isset($param[2]) ? $param[2] : '');
            }
        }
        if ((isset($param[1])) && ($param[1] == '1')) {
            $value = @html_entity_decode($value, ENT_QUOTES, get_charset());
        }
        if ((!isset($param[2])) || ($param[2] == '0')) {
            $value = trim(cms_preg_replace_safe('#(\s|&nbsp;)+#', ' ', $value));
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_TRUNCATE_LEFT($lang, $escaped, $param)
{
    $value = symbol_truncator($param, 'left');

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_TRUNCATE_SPREAD($lang, $escaped, $param)
{
    $value = symbol_truncator($param, 'spread');

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Handle truncation symbols in all their complexity
 *
 * @param  array $param Parameters passed to the symbol (0=text, 1=amount, 2=tooltip?, 3=is_html?, 4=use as grammatical length rather than HTML byte length, 5=fractional-deviation-tolerance for grammar-preservation)
 * @param  string $type The type of truncation to do
 * @set    left right spread
 * @param  ?mixed $tooltip_if_truncated Tooltip to add on, but only if we end up creating our own tooltip (null: none)
 * @return string The result.
 */
function symbol_truncator($param, $type, $tooltip_if_truncated = null)
{
    $value = '';

    if (is_object($param[0])) {
        $param[0] = $param[0]->evaluate();
        if (!isset($param[2])) {
            $param[2] = '0';
        }
        $param[3] = '1';
    }

    if ($GLOBALS['XSS_DETECT']) {
        $is_escaped = ocp_is_escaped($param[0]);
    }

    $amount = intval(isset($param[1]) ? $param[1] : '60');
    $is_html = ((isset($param[3])) && ($param[3] == '1'));

    if (strlen($param[0]) < $amount) {
        if ($is_html) {
            if ($GLOBALS['XSS_DETECT']) {
                if ($is_escaped) {
                    ocp_mark_as_escaped($param[0]);
                }
            }
            return $param[0];
        } else {
            return escape_html($param[0]);
        }
    }

    if ($is_html) {
        $not_html = strip_html($param[0]); // In case it contains HTML. This is imperfect, but having to cut something up is imperfect from the offset.
        $html = $param[0];
        if (($html == $not_html) && (strpos($html, '&') === false) && (strpos($html, '<') === false)) {
            $is_html = false; // Conserve memory
        }
    } else {
        $not_html = $param[0];
        $html = escape_html($param[0]);
    }

    if ((isset($not_html[$amount])/*optimisation*/) && ((cms_mb_strlen($not_html) > $amount)) || (stripos($html, '<img') !== false)) {
        $tooltip = ((isset($param[2])) && ($param[2] == '1'));
        $literal_pos = isset($param[4]) ? ($param[4] == '1') : false;
        $grammar_completeness_tolerance = isset($param[5]) ? floatval($param[5]) : 0.0;

        if ($is_html || $grammar_completeness_tolerance != 0.0) {
            require_code('xhtml');
        }

        $truncated = $not_html;
        switch ($type) {
            case 'left':
                $temp = (($is_html || $grammar_completeness_tolerance != 0.0) ? xhtml_substr($html, 0, max($amount - 3, 1), $literal_pos, false, $grammar_completeness_tolerance) : escape_html(cms_mb_substr($not_html, 0, max($amount - 3, 1))));
                if ($temp != $html && in_array(substr($temp, -1), array('.', '?', '!'))) {
                    $temp .= '<br class="ellipsis_break" />'; // so the "..." does not go right after the sentence terminator
                }
                $truncated = ($temp == $html) ? $temp : str_replace(array('</p>&hellip;', '</div>&hellip;'), array('&hellip;</p>', '&hellip;</div>'), (cms_trim($temp, true) . '&hellip;'));
                break;
            case 'expand':
                $temp = (($is_html || $grammar_completeness_tolerance != 0.0) ? xhtml_substr($html, 0, max($amount - 3, 1), $literal_pos, false, $grammar_completeness_tolerance) : escape_html(cms_mb_substr($not_html, 0, max($amount - 3, 1))));
                if ($temp != $html && in_array(substr($temp, -1), array('.', '?', '!'))) {
                    $temp .= '<br class="ellipsis_break" />'; // so the "..." does not go right after the sentence terminator
                }
                $_truncated = do_template('COMCODE_HIDE', array('_GUID' => '3ead7fdb5b510930f54310e3c32147c2', 'TEXT' => protect_from_escaping($temp), 'CONTENT' => protect_from_escaping($html)));
                $truncated = $_truncated->evaluate();
                break;
            case 'right':
                $truncated = str_replace(array('</p>&hellip;', '</div>&hellip;'), array('&hellip;</p>', '&hellip;</div>'), ('&hellip;' . ltrim(($is_html || $grammar_completeness_tolerance != 0.0) ? xhtml_substr($html, -max($amount - 3, 1), null, $literal_pos, false, $grammar_completeness_tolerance) : escape_html(cms_mb_substr($not_html, -max($amount - 3, 1))))));
                break;
            case 'spread':
                $pos = intval(floor(floatval($amount) / 2.0)) - 1;
                $truncated = str_replace(array('</p>&hellip;', '</div>&hellip;'), array('&hellip;</p>', '&hellip;</div>'), cms_trim((($is_html || $grammar_completeness_tolerance != 0.0) ? xhtml_substr($html, 0, $pos, $literal_pos, false, $grammar_completeness_tolerance) : escape_html(cms_mb_substr($not_html, 0, $pos))) . '&hellip;' . ltrim(($is_html || $grammar_completeness_tolerance != 0.0) ? xhtml_substr($html, -$pos - 1) : escape_html(cms_mb_substr($not_html, -$pos - 1))), true));
                break;
        }

        if ($tooltip) {
            if (!is_null($tooltip_if_truncated)) {
                $tif = (is_object($tooltip_if_truncated) ? $tooltip_if_truncated->evaluate() : $tooltip_if_truncated);
                if (strpos($tif, $html) !== false) {
                    $html = $tif;
                } else {
                    $html .= ' &ndash; ' . $tif;
                }
            }
            $tpl = ((strpos($truncated, '<div') !== false || strpos($truncated, '<p') !== false || strpos($truncated, '<table') !== false) ? 'CROP_TEXT_MOUSE_OVER' : 'CROP_TEXT_MOUSE_OVER_INLINE');
            $value_tempcode = do_template($tpl, array('_GUID' => '36ae945ed864633cfa0d67e5c3f2d1c8', 'TEXT_SMALL' => $truncated, 'TEXT_LARGE' => $html));
            $value = $value_tempcode->evaluate();
            if ($GLOBALS['XSS_DETECT']) {
                ocp_mark_as_escaped($value);
            }
        } else {
            $value = $truncated;
        }
    } else {
        $value = $html;
    }

    if ($GLOBALS['XSS_DETECT']) {
        if ($is_escaped || !$is_html/*Will have been explicitly escaped by this function*/) {
            ocp_mark_as_escaped($value);
        }
    }

    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_PARAGRAPH($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $is_blocky_already = (trim($param[0]) == '') || (preg_match('#<(p|div|ul|ol|dl|blockquote|h1|h2|h3|h4|h5|h6|table|iframe)(\s.*)?' . '>#', $param[0]) != 0);
        $value .= ($is_blocky_already ? '' : '<p>') . $param[0] . ($is_blocky_already ? '' : '</p>');
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_COMMA_LIST_GET($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[1])) {
        require_code('blocks');
        $values = block_params_str_to_arr($param[0]);
        $value = isset($values[$param[1]]) ? $values[$param[1]] : '';
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IS_EMPTY($lang, $escaped, $param)
{
    $value = '1';

    if (isset($param[0])) {
        $value = ($param[0] === '') ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IS_NON_EMPTY($lang, $escaped, $param)
{
    $value = '0';

    if (isset($param[0])) {
        $value = ($param[0] !== '') ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_CDN_FILTER($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $value = cdn_filter($param[0]);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_LOAD_PANEL($lang, $escaped, $param)
{
    $temp_array = array();
    handle_symbol_preprocessing(array($escaped, TC_SYMBOL, 'LOAD_PANEL', $param), $temp_array); // Late preprocessing. Should not be needed in case of full screen output (as this was properly preprocessed), but is in other cases

    foreach ($param as $i => $p) {
        if (is_object($p)) {
            $param[$i] = $p->evaluate();
        }
    }

    global $PANELS_CACHE;
    if (strpos($param[0], ':') !== false) {
        $param = array_reverse(explode(':', $param[0], 2));
    }
    if (substr($param[0], 0, 6) == 'panel_') {
        $param[0] = substr($param[0], 6);
    }
    $sr = serialize($param);
    $value = array_key_exists($sr, $PANELS_CACHE) ? $PANELS_CACHE[$sr] : '';

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_JS_ON($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        $value = has_js() ? $param[0] : (isset($param[1]) ? $param[1] : '');
    } else {
        $value = has_js() ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_ZONE($lang, $escaped, $param)
{
    $value = get_zone_name();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_PAGE($lang, $escaped, $param)
{
    $value = get_page_name();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HEADER_TEXT($lang, $escaped, $param)
{
    global $ZONE, $SHORT_TITLE, $DISPLAYED_TITLE;
    if ($ZONE === null) {
        load_zone_data();
    }
    if ($SHORT_TITLE === null) { // Take from either zone header or screen title
        if ($DISPLAYED_TITLE !== null) {
            $_displayed_title = $DISPLAYED_TITLE->evaluate();
        }
        if (($DISPLAYED_TITLE !== null) && (strip_tags($_displayed_title) != '')) {
            $value = strip_html(preg_replace('#<a[^<>]*>.*</a>#U', '', $_displayed_title)); // The regexp is to remove possible FRACTIONAL_EDIT.tpl link
        } else {
            if ($ZONE !== null) {
                $value = get_translated_text($ZONE['zone_header_text']);
            }
        }
    } else { // Take from short title
        $comcodeless = strip_comcode($SHORT_TITLE); // This is not HTML

        // Strip 'Welcome to' off if it's there
        $value = cms_preg_replace_safe('#' . preg_quote(do_lang('WELCOME_TO_STRIPPABLE') . ' ' . get_site_name(), '#') . '([^\-]+\s*-\s*)?#', '', $comcodeless);

        // Strip site name off it it's there (it'll be put on in the templates, so we don't want it twice)
        $stub = get_site_name() . ' - ';
        if (substr($value, strlen($stub)) == $stub) {
            $value = substr($value, strlen($stub));
        }
        if ($value == get_site_name()) {
            $value = '';
        }
    }
    $value = trim($value);

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_CANONICAL_URL($lang, $escaped, $param)
{
    global $NON_CANONICAL_PARAMS, $CANONICAL_URL;
    if ($CANONICAL_URL === null) {
        $non_canonical = array();
        if (is_array($NON_CANONICAL_PARAMS)) {
            foreach (array_keys($NON_CANONICAL_PARAMS) as $n) {
                $non_canonical[$n] = null;
            }
        }
        $CANONICAL_URL = get_self_url(true, false, $non_canonical);
    }
    $value = $CANONICAL_URL;

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_SHOW_HEADER($lang, $escaped, $param)
{
    $value = (is_wide_high() == 1) ? '0' : '1';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_SHOW_FOOTER($lang, $escaped, $param)
{
    $value = (is_wide_high() == 1) ? '0' : '1';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_WIDE($lang, $escaped, $param)
{
    $value = (is_wide() == 1) ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_WIDE_HIGH($lang, $escaped, $param)
{
    $value = (is_wide_high() == 1) ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_LOGO_URL($lang, $escaped, $param)
{
    $value = get_logo_url();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HELPER_PANEL_TUTORIAL($lang, $escaped, $param)
{
    if ($GLOBALS['HELPER_PANEL_TUTORIAL'] === null) {
        set_helper_panel_tutorial('');
    }
    if (get_option('show_docs') == '0') {
        set_helper_panel_tutorial('');
    }
    $value = $GLOBALS['HELPER_PANEL_TUTORIAL'];

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HELPER_PANEL_TEXT($lang, $escaped, $param)
{
    if ($GLOBALS['HELPER_PANEL_TEXT'] === null) {
        $GLOBALS['HELPER_PANEL_TEXT'] = '';
    }
    $value = is_object($GLOBALS['HELPER_PANEL_TEXT']) ? $GLOBALS['HELPER_PANEL_TEXT']->evaluate() : $GLOBALS['HELPER_PANEL_TEXT'];

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_SHOW_DOCS($lang, $escaped, $param)
{
    $value = (get_option('show_docs') === '0') ? '0' : '1';

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MESSAGES_TOP($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if ($GLOBALS['ATTACHED_MESSAGES'] !== null) {
        $value = static_evaluate_tempcode($GLOBALS['ATTACHED_MESSAGES']);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MESSAGES_BOTTOM($lang, $escaped, $param)
{
    // Extra stuff we can tag on (like messages)
    $messages_bottom = new Tempcode();
    if (get_option('site_closed') == '1') {
        require_code('global4');
        attach_message_site_closed($messages_bottom);
    }
    if ($GLOBALS['IS_ACTUALLY_ADMIN']) {
        require_code('global4');
        attach_message_su($messages_bottom);
    }
    if (get_param_string('special_page_type', '') == 'memory') {
        require_code('view_modes');
        attach_message_memory_usage($messages_bottom);
    }
    $value = $messages_bottom->evaluate();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_LATE_MESSAGES($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if ($GLOBALS['LATE_ATTACHED_MESSAGES'] !== null) {
        $value = static_evaluate_tempcode($GLOBALS['LATE_ATTACHED_MESSAGES']);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_BREADCRUMBS($lang, $escaped, $param)
{
    $show_self = (!isset($param[0]) || $param[0] == '1');
    if (!$show_self) {
        $GLOBALS['BREADCRUMBS'] = null;
    }
    $value = static_evaluate_tempcode(breadcrumbs($show_self));

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HAS_SU($lang, $escaped, $param)
{
    $value = '0';
    if (!is_guest()) {
        $value = (get_option('show_su') == '1') && (has_privilege(get_member(), 'assume_any_member')) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_STAFF_ACTIONS($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (!is_guest()) {
        // Different types of page type for staff (debug view, etc)
        if ((get_option('show_staff_page_actions') == '1') && (has_privilege(get_member(), 'view_profiling_modes')) && (!has_interesting_post_fields())) { // We count POST because we don't want to allow double submits
            require_code('site2');
            $value = get_staff_actions_list();
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_TRIM($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $value = $param[0];
        if ($value !== '') {
            if (strpos($value, '<') === false && strpos($value, '&') === false) {
                $value = trim($value);
            } else {
                $value = cms_trim($param[0], !isset($param[1]) || $param[1] === '1');
            }
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Trim some text, supporting removing HTML white-space also.
 *
 * @param  string $text Input text.
 * @param  boolean $try_hard Whether to keep doing it, while it changes (if complex mixtures are on the end).
 * @return string The result text.
 */
function cms_trim($text, $try_hard = true)
{
    if ((preg_match('#[<&]#', $text) === 0) && (memory_get_usage() > 1024 * 1024 * 40)) {
        return trim($text); // Don't have enough memory
    }

    if ($GLOBALS['XSS_DETECT']) {
        $is_escaped = ocp_is_escaped($text);
    }

    // Intentionally not using regexps, as actually using substr is a lot faster and uses much less memory

    do {
        $before = $text;
        $c = substr($text, 0, 1);
        if ($c === '<') {
            if (strtolower(substr($text, 1, 1)) === 'b') {
                if (strtolower(substr($text, 0, 6)) === '<br />') {
                    $text = substr($text, 6);
                }
                if (strtolower(substr($text, 0, 5)) === '<br/>') {
                    $text = substr($text, 5);
                }
                if (strtolower(substr($text, 0, 4)) === '<br>') {
                    $text = substr($text, 4);
                }
            }
        }
        elseif ($c == '&') {
            if (strtolower(substr($text, 0, 6)) === '&nbsp;') {
                $text = substr($text, 6);
            }
        }
        $text = ltrim($text);
    } while (($try_hard) && ($before !== $text));
    do {
        $before = $text;
        $c = substr($text, -1, 1);
        if ($c === '>') {
            if (strtolower(substr($text, -6)) === '<br />') {
                $text = substr($text, 0, -6);
            }
            if (strtolower(substr($text, -5)) === '<br/>') {
                $text = substr($text, 0, -5);
            }
            if (strtolower(substr($text, -4)) === '<br>') {
                $text = substr($text, 0, -4);
            }
        }
        elseif ($c == ';') {
            if (strtolower(substr($text, -6)) === '&nbsp;') {
                $text = substr($text, 0, -6);
            }
        }
        $text = rtrim($text);
    } while (($try_hard) && ($before !== $text));

    if ($GLOBALS['XSS_DETECT']) {
        if ($is_escaped) {
            ocp_mark_as_escaped($text);
        }
    }

    return $text;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_CPF_VALUE($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $_value = '';

        if (is_numeric($param[0])) {
            require_code('cns_members');
            $custom_fields = cns_get_all_custom_fields_match_member(isset($param[1]) ? intval($param[1]) : get_member());
            foreach ($custom_fields as $custom_field) {
                if ($custom_field['FIELD_ID'] == $param[0]) {
                    $_value = $custom_field[empty($param[2]) ? 'RAW' : 'RENDERED'];
                }
            }
        } elseif ((substr($param[0], 0, 2) == 'm_') && (stripos($param[0], 'hash') === false) && (stripos($param[0], 'salt') === false)) {
            $_value = $GLOBALS['FORUM_DRIVER']->get_member_row_field(isset($param[1]) ? intval($param[1]) : get_member(), $param[0]);
        } else {
            if (preg_match('#^[a-z\_\d]*$#', $param[0]) != 0) {
                $_value = get_cms_cpf($param[0], isset($param[1]) ? intval($param[1]) : null);
            } else {
                require_code('cns_members');
                $cpf_id = find_cpf_field_id($param[0]);
                if (!is_null($cpf_id)) {
                    require_code('cns_members');
                    $custom_fields = cns_get_all_custom_fields_match_member(isset($param[1]) ? intval($param[1]) : get_member());
                    foreach ($custom_fields as $custom_field) {
                        if ($custom_field['FIELD_ID'] == strval($cpf_id)) {
                            $_value = $custom_field[empty($param[2]) ? 'RAW' : 'RENDERED'];
                        }
                    }
                }
            }
        }

        if (!is_string($_value)) {
            $value = is_null($_value) ? '' : strval($_value);
        } else {
            $value = $_value;
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_BANNER($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (addon_installed('banners')) {
        global $SITE_INFO;
        $is_on_banners = ((isset($param[1])) && ($param[1] == '1')) || (((!has_privilege(get_member(), 'banner_free')) || (($GLOBALS['FORUM_DRIVER']->is_super_admin(get_member())) && (get_option('admin_banners') == '1')) || (!is_null($GLOBALS['CURRENT_SHARE_USER']))));
        if (!empty($SITE_INFO['throttle_bandwidth_registered'])) {
            $views_till_now = intval(get_value('page_views'));
            $bandwidth_allowed = $SITE_INFO['throttle_bandwidth_registered'];
            $total_bandwidth = intval(get_value('download_bandwidth'));
            if ($bandwidth_allowed * 1024 * 1024 >= $total_bandwidth) {
                $is_on_banners = false;
            }
        }
        if (($is_on_banners) && (!is_page_https(get_zone_name(), get_page_name()))) { // We can't show when HTTPS, due to HTTPS security warnings (can't show HTTP requests on HTTPS page, and banner has them by nature).
            require_code('banners');

            $b_type = isset($param[0]) ? $param[0] : '';
            if (!$GLOBALS['STATIC_TEMPLATE_TEST_MODE']) { // Normal operation
                $width = empty($param[1]) ? null : intval($param[1]);
                $height = empty($param[2]) ? null : intval($param[2]);
                $region = isset($param[3]) ? $param[3] : null;
                $name = isset($param[4]) ? $param[4] : null;
                $_value = banners_script(true, '', $name, $b_type, '', $width, $height, $region);
                $value = trim($_value->evaluate());
            } else { // Been told to behave statically
                $value = 'Banner goes here';
            }
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_AVATAR($lang, $escaped, $param)
{
    $value = $GLOBALS['FORUM_DRIVER']->get_member_avatar_url(isset($param[0]) ? intval($param[0]) : get_member());

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IS_GUEST($lang, $escaped, $param)
{
    if (isset($param[0])) {
        $value = (is_guest(intval($param[0]))) ? '1' : '0';
    } else {
        $value = is_guest() ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MEMBER($lang, $escaped, $param)
{
    if (!isset($param[0])) {
        $value = strval(get_member());
    } else {
        $member_id = $GLOBALS['FORUM_DRIVER']->get_member_from_username($param[0]);
        $value = is_null($member_id) ? '' : strval($member_id);
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_REQUIRE_CSS($lang, $escaped, $param)
{
    if (isset($param[0])) {
        require_css($param[0]);
    }

    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IS_HTTPAUTH_LOGIN($lang, $escaped, $param)
{
    $value = is_httpauth_login() ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MEMBER_PROFILE_URL($lang, $escaped, $param)
{
    $member_id = ((!is_null($param)) && (isset($param[0]))) ? intval($param[0]) : get_member();
    $value = $GLOBALS['FORUM_DRIVER']->member_profile_url($member_id, false, true);
    if (is_object($value)) {
        $value = $value->evaluate();
    }
    if (is_null($value)) {
        $value = '';
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_USERNAME($lang, $escaped, $param)
{
    $member_id = (isset($param[0])) ? intval($param[0]) : get_member();
    $value = $GLOBALS['FORUM_DRIVER']->get_username($member_id, (isset($param[1])) && ($param[1] == '1'));
    if ($value === null) {
        $value = do_lang('UNKNOWN');
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_DISPLAYED_USERNAME($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $value = get_displayname($param[0]);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_CYCLE($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        global $CYCLES;
        if (!isset($CYCLES[$param[0]])) {
            $CYCLES[$param[0]] = 0;
        }
        if (!isset($param[1])) { // If we can't find a param simply return the index. Poor-mans cycle reader.
            $value = strval($CYCLES[$param[0]]);
        } else { // Cycle
            if (count($param) == 2) {
                $param = array_merge(array($param[0]), explode(',', $param[1]));
            }

            ++$CYCLES[$param[0]];
            if (!array_key_exists($CYCLES[$param[0]], $param)) {
                $CYCLES[$param[0]] = 1;
            }
            $value = $param[$CYCLES[$param[0]]];
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_THUMBNAIL($lang, $escaped, $param)
{
    require_code('images');
    $value = _symbol_thumbnail($param);

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IS_IN_GROUP($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        if (in_array($param[count($param) - 1], array('', 'primary', 'secondary'))) {
            $last_param = $param[count($param) - 1];
            unset($param[count($param) - 1]);
        } else {
            $last_param = '';
        }

        $member_id = get_member();
        $new_param = '';
        $param_2 = array();
        foreach ($param as $group) {
            if ((substr($group, 0, 1) == '@') && (is_numeric(substr($group, 1)))) {
                $member_id = intval(substr($group, 1));
            } else {
                $param_2 = array_merge($param_2, explode(',', $group));
            }
        }
        foreach ($param_2 as $group) {
            if ($new_param != '') {
                $new_param .= ',';
            }
            $new_param .= $group;
        }

        if ($last_param == 'primary') {
            $member_row = $GLOBALS['FORUM_DRIVER']->get_member_row($member_id);
            $real_group_list = array($GLOBALS['FORUM_DRIVER']->mrow_group($member_row));
        } elseif ($last_param == 'secondary') {
            $real_group_list = $GLOBALS['FORUM_DRIVER']->get_members_groups($member_id);
            $member_row = $GLOBALS['FORUM_DRIVER']->get_member_row($member_id);
            $real_group_list = array_diff($real_group_list, array($GLOBALS['FORUM_DRIVER']->mrow_group($member_row)));
        } else {
            $real_group_list = $GLOBALS['FORUM_DRIVER']->get_members_groups($member_id);
        }
        require_code('selectcode');
        $value = (count(array_intersect(selectcode_to_idlist_using_memory($new_param, $GLOBALS['FORUM_DRIVER']->get_usergroup_list()), $real_group_list)) != 0) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IS_STAFF($lang, $escaped, $param)
{
    if ((isset($GLOBALS['FORUM_DRIVER'])) && (function_exists('get_member'))) {
        $value = $GLOBALS['FORUM_DRIVER']->is_staff(((!is_null($param)) && (isset($param[0]))) ? intval($param[0]) : get_member()) ? '1' : '0';
    } else {
        $value = '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IS_ADMIN($lang, $escaped, $param)
{
    if ((isset($GLOBALS['FORUM_DRIVER'])) && (function_exists('get_member'))) {
        $value = $GLOBALS['FORUM_DRIVER']->is_super_admin(((!is_null($param)) && (isset($param[0]))) ? intval($param[0]) : get_member()) ? '1' : '0';
    } else {
        $value = '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_PHOTO($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    $value = $GLOBALS['FORUM_DRIVER']->get_member_photo_url(isset($param[0]) ? intval($param[0]) : get_member());

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_CNS_RANK_IMAGE($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (addon_installed('cns_forum')) {
        require_code('cns_groups');
        $rank_images = new Tempcode();
        $member_id = isset($param[0]) ? intval($param[0]) : get_member();
        $posters_groups = $GLOBALS['FORUM_DRIVER']->get_members_groups($member_id, true);
        foreach ($posters_groups as $group) {
            $rank_image = cns_get_group_property($group, 'rank_image');
            $group_leader = cns_get_group_property($group, 'group_leader');
            $group_name = cns_get_group_name($group);
            $rank_image_pri_only = cns_get_group_property($group, 'rank_image_pri_only');
            if (($rank_image != '') && (($rank_image_pri_only == 0) || ($group == $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_primary_group')))) {
                $rank_images->attach(do_template('CNS_RANK_IMAGE', array('_GUID' => '513032ef4693abc353f9934e8799943b', 'USERNAME' => $GLOBALS['FORUM_DRIVER']->get_username($member_id), 'GROUP_NAME' => $group_name, 'IMG' => $rank_image, 'IS_LEADER' => $group_leader == $member_id)));
            }
        }
        $value = $rank_images->evaluate();
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_URL_FOR_GET_FORM($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $url_bits = parse_url($param[0]);
        if (array_key_exists('scheme', $url_bits)) {
            $value = $url_bits['scheme'] . '://' . (array_key_exists('host', $url_bits) ? $url_bits['host'] : 'localhost');
            if ((array_key_exists('port', $url_bits)) && ($url_bits['port'] != 80)) {
                $value .= ':' . strval($url_bits['port']);
            }
        }
        if (array_key_exists('path', $url_bits)) {
            $value .= $url_bits['path'];
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HIDDENS_FOR_GET_FORM($lang, $escaped, $param)
{
    $_value = new Tempcode();
    $url_bits = parse_url($param[0]);
    if ((array_key_exists('query', $url_bits)) && ($url_bits['query'] != '')) {
        foreach (explode('&', $url_bits['query']) as $exp) {
            $parts = explode('=', $exp, 2);
            if (count($parts) == 2) {
                if ((!in_array($parts[0], $param)) && (!in_array(preg_replace('#\d+#', '*', $parts[0]), $param)) && (!in_array(preg_replace('#filter_\w+#', 'filter_*', $parts[0]), $param))) {
                    $_value->attach(form_input_hidden($parts[0], urldecode($parts[1])));
                }
            }
        }
    }
    $value = $_value->evaluate();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_NOTIFICATIONS_ENABLED($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        require_code('notifications');
        $value = notifications_enabled(array_key_exists(1, $param) ? $param[1] : get_page_name(), $param[0]) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_NOTIFICATIONS_AVAILABLE($lang, $escaped, $param)
{
    $value = '1';
    if (isset($param[0])) {
        $notification_code = $param[0];

        require_code('notifications');

        if (notification_locked_down($notification_code) === 0) {
            $value = '0';
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_AUTHOR_MEMBER($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        if (addon_installed('authors')) {
            require_code('authors');
            $member_id = get_author_id_from_name($param[0]);
            if ($member_id === null) {
                $member_id = $GLOBALS['FORUM_DRIVER']->get_guest_id();
            }
            $value = strval($member_id);
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MAKE_RELATIVE_DATE($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        if ((get_option('use_contextual_dates') == '0') && ((!array_key_exists(1, $param)) || ($param[1] != '1'))) {
            $value = get_timezoned_date(intval($param[0]));
        } else {
            $value = display_time_period(time() - intval($param[0]));
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_LOAD_PAGE($lang, $escaped, $param)
{
    $temp_array = array();
    handle_symbol_preprocessing(array($escaped, TC_SYMBOL, 'LOAD_PAGE', $param), $temp_array); // Late preprocessing. Should not be needed in case of full screen output (as this was properly preprocessed), but is in other cases

    foreach ($param as $i => $p) {
        if (is_object($p)) {
            $param[$i] = $p->evaluate();
        }
    }

    global $PAGES_CACHE;
    if (strpos($param[0], ':') !== false) {
        $param = array_reverse(explode(':', $param[0], 2));
    }
    $_value = $PAGES_CACHE[serialize($param)];
    $value = $_value->evaluate();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_RUNNING_SCRIPT($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        $value = running_script($param[0]) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MATCH_KEY_MATCH($lang, $escaped, $param)
{
    $value = '0';
    foreach ($param as $match_key) {
        if (($match_key == '1') || ($match_key == '0') || ($match_key == '')) {
            continue;
        }
        if (match_key_match($match_key, ((isset($param[1])) && ($match_key == '1')))) {
            $value = '1';
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_BLOCK($lang, $escaped, $param)
{
    if (!$GLOBALS['STATIC_TEMPLATE_TEST_MODE']) { // Normal operation
        $temp_array = array();
        handle_symbol_preprocessing(array($escaped, TC_SYMBOL, 'BLOCK', $param), $temp_array); // Late preprocessing. Should not be needed in case of full screen output (as this was properly preprocessed), but is in other cases

        foreach ($param as $i => $p) {
            if (is_object($p)) {
                $param[$i] = $p->evaluate();
            }
        }

        if ((count($param) == 1) && (strpos($param[0], ',') !== false)) { // NB: This code is also in Tempcode.php
            $param_2 = block_params_str_to_arr($param[0], true);
        } else {
            $param_2 = $param;
        }

        foreach ($param_2 as &$_param) {
            $_param = preg_replace('#^\s*([^\s]+)\s*=#', '$1=', $_param);
        }

        if (in_array('defer=1', $param_2)) {
            $value = static_evaluate_tempcode(do_template('JS_BLOCK', array('_GUID' => '2334719e23b2773ad04fe0fcbdce684d', 'BLOCK_PARAMS' => block_params_arr_to_str($param_2))));
        } else {
            global $BLOCKS_CACHE;
            if (isset($BLOCKS_CACHE[serialize($param_2)])) { // Will always be set
                $value = $BLOCKS_CACHE[serialize($param_2)]->evaluate();
            } else {
                $value = '';
                if ($GLOBALS['XSS_DETECT']) {
                    ocp_mark_as_escaped($value);
                }
            }
        }
    } else {
        $value = '';
        if ($GLOBALS['XSS_DETECT']) {
            ocp_mark_as_escaped($value);
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_FORCE_PREVIEWS($lang, $escaped, $param)
{
    if (get_option('forced_preview_option') == '1') {
        if (get_forum_type() == 'cns') {
            if ((is_guest()) && (get_option('default_preview_guests') == '0')) {
                $value = '0';
            } else {
                $value = ($GLOBALS['FORUM_DRIVER']->get_member_row_field(get_member(), 'm_preview_posts') == 1) ? '1' : '0';
            }
        } else {
            $value = (get_option('default_preview_guests') == '0') ? '0' : '1';
        }
    } else {
        $value = '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_PREVIEW_URL($lang, $escaped, $param)
{
    $value = find_script('preview');
    $value .= '?page=' . urlencode(get_page_name());
    $value .= '&type=' . urlencode(get_param_string('type', '', true));

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HIDE_HELP_PANEL($lang, $escaped, $param)
{
    $value = ((array_key_exists('hide_helper_panel', $_COOKIE)) && ($_COOKIE['hide_helper_panel'] == '1')) ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_FIND_SCRIPT_NOHTTP($lang, $escaped, $param)
{
    if ($GLOBALS['DEV_MODE']) {// Dev mode changes base domain so we need to actually use it in full (fine, we don't have HTTPS in dev mode).
        return ecv_FIND_SCRIPT($lang, $escaped, $param);
    }

    $value = preg_replace('#^https?://[^/]+#', '', ecv_FIND_SCRIPT($lang, array(), $param));
    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_FIND_SCRIPT($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if ((isset($param[0])) && (function_exists('find_script'))) {
        $value = find_script($param[0], false, isset($param[1]) ? intval($param[1]) : 0);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_CSS_TEMPCODE($lang, $escaped, $param)
{
    $temp_array = array();
    handle_symbol_preprocessing(array($escaped, TC_SYMBOL, 'CSS_TEMPCODE', $param), $temp_array); // Late preprocessing. Should not be needed in case of full screen output (as this was properly preprocessed), but is in other cases

    $_value = css_tempcode();
    $value = $_value->evaluate();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_JS_TEMPCODE($lang, $escaped, $param)
{
    $temp_array = array();
    handle_symbol_preprocessing(array($escaped, TC_SYMBOL, 'JS_TEMPCODE', $param), $temp_array); // Late preprocessing. Should not be needed in case of full screen output (as this was properly preprocessed), but is in other cases

    $_value = javascript_tempcode(((isset($param[0])) && ($param[0]) != '') ? $param[0] : null);
    $value = $_value->evaluate();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_PAGE_TITLE($lang, $escaped, $param)
{
    global $DISPLAYED_TITLE;
    $value = is_null($DISPLAYED_TITLE) ? '' : $DISPLAYED_TITLE->evaluate();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_EXTRA_HEAD($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if ($GLOBALS['EXTRA_HEAD'] !== null) {
        $_value = $GLOBALS['EXTRA_HEAD'];
        $value = $_value->evaluate();
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_EXTRA_FOOT($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if ($GLOBALS['EXTRA_FOOT'] !== null) {
        $_value = $GLOBALS['EXTRA_FOOT'];

        if (array_key_exists(0, $param)) { // Set
            $GLOBALS['EXTRA_FOOT']->attach($param[0]);
        } else { // Get
            $value = $_value->evaluate();
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_RAND($lang, $escaped, $param)
{
    if (!$GLOBALS['STATIC_TEMPLATE_TEST_MODE']) { // Normal operation
        if (isset($param[1])) {
            $min = intval($param[0]);
            $max = intval($param[1]);
        } elseif (isset($param[0])) {
            $min = 0;
            $max = intval($param[0]);
        } else {
            $min = 0;
            $max = mt_getrandmax();
        }
        if ($min > $max) {
            $tmp = $min;
            $min = $max;
            $max = $tmp;
        }

        static $before = array(); // Don't allow repeats
        $key = strval($min) . '_' . strval($max);
        if (!isset($before[$key])) {
            $before[$key] = array();
        }
        do {
            $random = mt_rand($min, $max);
        }
        while (isset($before[$key][$random]));
        if (count($before[$key]) < $max - $min) {
            $before[$key][$random] = true;
        } else { // Reset, so we get another set to randomise through
            $before[$key] = array();
        }

        $value = strval($random);
    } else { // Been told to behave statically
        $value = '4';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_SET_RAND($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        if (!$GLOBALS['STATIC_TEMPLATE_TEST_MODE']) { // Normal operation
            $value = $param[mt_rand(0, count($param) - 1)];
        } else { // Been told to behave statically
            $value = $param[0];
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MEMBER_EMAIL($lang, $escaped, $param)
{
    $value = $GLOBALS['FORUM_DRIVER']->get_member_email_address(isset($param[0]) ? intval($param[0]) : get_member());

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HAS_PRIVILEGE($lang, $escaped, $param)
{
    $value = '';

    if ((isset($param[0])) && (function_exists('has_privilege'))) {
        $value = has_privilege(((!is_null($param)) && (isset($param[1]))) ? intval($param[1]) : get_member(), $param[0]) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HAS_ZONE_ACCESS($lang, $escaped, $param)
{
    $value = '';

    if ((isset($param[0])) && (function_exists('has_zone_access'))) {
        $value = has_zone_access(((!is_null($param)) && (isset($param[1]))) ? intval($param[1]) : get_member(), $param[0]) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HAS_DELETE_PERMISSION($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        $range = strtolower($param[0]);
        $owner = intval($param[1]);
        $member = ((!is_null($param)) && (isset($param[2]))) ? intval($param[2]) : get_member();
        $cms_page = ((!is_null($param)) && (isset($param[3]))) ? $param[3] : get_page_name();
        if (array_key_exists(5, $param)) {
            $value = has_delete_permission($range, $member, $owner, $cms_page, array($param[5], $param[6])) ? '1' : '0';
        } else {
            $value = has_delete_permission($range, $member, $owner, $cms_page) ? '1' : '0';
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_DATE_AND_TIME($lang, $escaped, $param)
{
    $use_contextual_dates = (isset($param[0]) && ($param[0] == '1'));
    $verbose = (isset($param[1]) && ($param[1] == '1'));
    $server_time = (isset($param[2]) && ($param[2] == '1'));
    $time = ((isset($param[3])) && ($param[3] != '')) ? intval($param[3]) : time();
    $member = isset($param[4]) ? intval($param[2]) : null;
    $value = get_timezoned_date($time, true, $verbose, $server_time, !$use_contextual_dates, $member);

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_DATE($lang, $escaped, $param)
{
    $use_contextual_dates = (isset($param[0]) && ($param[0] === '1'));
    $verbose = (isset($param[1]) && ($param[1] === '1'));
    $server_time = (isset($param[2]) && ($param[2] === '1'));
    $time = (!empty($param[3])) ? intval($param[3]) : time();
    $member = isset($param[4]) ? intval($param[2]) : null;
    $value = get_timezoned_date($time, false, $verbose, $server_time, !$use_contextual_dates, $member);

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_TIME($lang, $escaped, $param)
{
    $time = (!empty($param[0])) ? intval($param[0]) : time();
    $use_contextual_dates = (isset($param[1]) && ($param[1] === '1'));
    $server_time = (isset($param[2]) && ($param[2] === '1'));
    $member = isset($param[3]) ? intval($param[3]) : null;
    $value = get_timezoned_time($time, !$use_contextual_dates, $member, $server_time);

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_FROM_TIMESTAMP($lang, $escaped, $param)
{
    if (isset($param[0])) {
        $timestamp = (!empty($param[1])) ? intval($param[1]) : time();

        if ($GLOBALS['STATIC_TEMPLATE_TEST_MODE']) {
            require_code('lorem');
            $timestamp = intval(placeholder_date_raw());
        }

        if ((!array_key_exists(2, $param)) || ($param[2] === '1')) {
            $timestamp = utctime_to_usertime($timestamp);
        }
        $value = cms_strftime($param[0], $timestamp);
        if ($value === $param[0]) {// If no conversion happened then the syntax must have been for 'date' not 'strftime'
            $value = date($param[0], $timestamp);
        }
    } else {
        if ($GLOBALS['STATIC_TEMPLATE_TEST_MODE']) {
            require_code('lorem');
            $value = placeholder_date_raw();
        } else {
            $timestamp = time();
            $value = strval($timestamp);
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_DEV_MODE($lang, $escaped, $param)
{
    $value = $GLOBALS['DEV_MODE'] ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_BROWSER_MATCHES($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        $q = false;
        foreach (explode('|', $param[0]) as $browser) {
            $q = browser_matches($browser);
            if ($q) {
                break;
            }
        }
        $value = $q ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_INIT($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        global $TEMPCODE_SETGET;
        if (!isset($TEMPCODE_SETGET[$param[0]])) {
            $TEMPCODE_SETGET[$param[0]] = $param[1];
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_INC($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        global $TEMPCODE_SETGET;
        if (!isset($TEMPCODE_SETGET[$param[0]])) {
            $TEMPCODE_SETGET[$param[0]] = '0';
        }
        $TEMPCODE_SETGET[$param[0]] = strval(intval($TEMPCODE_SETGET[$param[0]]) + 1);
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_PREG_REPLACE($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[2])) {
        $bak = $GLOBALS['SUPPRESS_ERROR_DEATH'];
        $GLOBALS['SUPPRESS_ERROR_DEATH'] = true;
        $value = preg_replace('#' . str_replace('#', '\#', $param[0]) . '#' . (isset($param[3]) ? str_replace('e', '', $param[3]) : ''), $param[1], $param[2]);
        $GLOBALS['SUPPRESS_ERROR_DEATH'] = $bak;
        if (isset($php_errormsg)) {
            attach_message($php_errormsg, 'warn');
        }

        if ($GLOBALS['XSS_DETECT'] && ocp_is_escaped($param[0])) {
            ocp_mark_as_escaped($value);
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MAX($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        $value = strval(max(intval($param[0]), intval($param[1])));
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MIN($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        $value = strval(min(intval($param[0]), intval($param[1])));
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_DIV_FLOAT($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        if (floatval($param[1]) == 0.0) {
            $value = 'divide-by-zero';
        } else {
            $value = float_to_raw_string(floatval($param[0]) / floatval($param[1]), 20, true);
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_DIV($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        if (floatval($param[1]) == 0.0) {
            $value = 'divide-by-zero';
        } else {
            $value = strval(intval(floor(floatval($param[0]) / floatval($param[1]))));
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_LCASE($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[0])) {
        $value = cms_mb_strtolower($param[0]);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    if ($GLOBALS['XSS_DETECT'] && ocp_is_escaped($param[0])) {
        ocp_mark_as_escaped($value);
    }

    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv__POST($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $value = post_param_string($param[0], isset($param[1]) ? $param[1] : '');
    }

    if ((!has_solemnly_declared(I_UNDERSTAND_XSS)) && ($escaped === array())) {
        $escaped = array(ENTITY_ESCAPED);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_REPLACE($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[2])) {
        $value = str_replace($param[0], $param[1], $param[2]);
    }

    if ($GLOBALS['XSS_DETECT'] && ocp_is_escaped($param[0])) {
        ocp_mark_as_escaped($value);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IN_STR($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        if ($param[1] == '') { // Would generate a PHP notice
            $value = '0';
        } else {
            $value = '0';
            foreach ($param as $i => $check) {
                if ((is_integer($i)) && ($i != 0) && ($check != '')) {
                    if (strpos($param[0], $check) !== false) {
                        $value = '1';
                        break;
                    }
                }
            }
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_SUBSTR_COUNT($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        if ($param[0] == '') {
            $value = '0';
        } else {
            $value = strval(substr_count($param[0], $param[1]));
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_SUBSTR($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[1])) {
        $value = cms_mb_substr($param[0], intval($param[1]), isset($param[2]) ? intval($param[2]) : strlen($param[0]));
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_ALTERNATOR_TRUNCATED($lang, $escaped, $param) // Alternate values according to whether some given text WOULD have been truncated. 0: text to check against, 1: the truncate length, 2:IF would not be do this, 3: if it would be do this, 4: whether given text is encoded as HTML (0=no [default, plain-text], 1=yes)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[3])) {
        $amount = intval($param[1]);
        $is_html = ((isset($param[4])) && ($param[4] == '1'));
        if (strlen($is_html ? strip_tags($param[0]) : $param[0]) > $amount) {
            $value = $param[3];
        } else {
            $value = $param[2];
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_EQ($lang, $escaped, $param)
{
    $value = '';

    if (!isset($param[0])) {
        $param[0] = '';
    }
    if (!isset($param[1])) {
        $param[1] = '';
    }
    $first = array_shift($param);
    $count = 0;
    foreach ($param as $test) {
        if ($first == $test) {
            $count++;
            break;
        }
    }
    $value = ($count !== 0) ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_NEQ($lang, $escaped, $param)
{
    $value = '';

    if (!isset($param[0])) {
        $param[0] = '';
    }
    if (!isset($param[1])) {
        $param[1] = '';
    }
    $first = array_shift($param);
    $count = 0;
    foreach ($param as $test) {
        if ($first == $test) {
            $count++;
        }
    }
    $value = ($count === 0) ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_NOT($lang, $escaped, $param)
{
    $value = '1';

    if (isset($param[0])) {
        $value = ($param[0] == '1') ? '0' : '1';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_OR($lang, $escaped, $param)
{
    $value = '';

    $count = 0;
    foreach ($param as $test) {
        if ($test == '1') {
            $count++;
        }
    }
    $value = ($count > 0) ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_AND($lang, $escaped, $param)
{
    $count = 0;
    $total = 0;
    foreach ($param as $test) {
        if ($test === '1') {
            $count++;
        }
        $total++;
    }
    $value = ($count === $total) ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_NOR($lang, $escaped, $param)
{
    $count = 0;
    foreach ($param as $test) {
        if ($test === '1') {
            $count++;
        }
    }
    $value = ($count > 0) ? '0' : '1';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_NAND($lang, $escaped, $param)
{
    $count = 0;
    foreach ($param as $test) {
        if ($test === '1') {
            $count++;
        }
    }
    $value = ($count === count($param)) ? '0' : '1';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_LT($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        $value = (intval($param[0]) < intval($param[1])) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_GT($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        $value = (intval($param[0]) > intval($param[1])) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_INSERT_SPAMMER_BLACKHOLE($lang, $escaped, $param)
{
    static $done_once = false;

    $value = '';

    if (!$GLOBALS['STATIC_TEMPLATE_TEST_MODE']) {
        if (get_option('spam_blackhole_detection') == '1' && !$done_once && get_page_name() != 'members'/*in case of some weird autocomplete issue when changing your password*/) {
            $field_name = 'y' . md5(get_site_name() . ': antispam');
            $tag = ((isset($param[0])) && ($param[0] == '1')) ? 'span' : 'div';
            $value .= '<' . $tag . ' id="' . escape_html($field_name) . '_wrap" style="display:none"><label for="' . escape_html($field_name) . '">' . do_lang('DO_NOT_FILL_ME_SPAMMER_BLACKHOLE') . '</label><input autocomplete="off" id="' . escape_html($field_name) . '" name="' . escape_html($field_name) . '" value="" type="text" /></' . $tag . '>';
            if (!$GLOBALS['SEMI_DEV_MODE']) {
                $value .= '<script>// <' . '![CDATA[' . "\n" . 'var wrap=document.getElementById(\'' . escape_html($field_name) . '_wrap\'); wrap.parentNode.removeChild(wrap);' . "\n" . '//]]></script>';
            }

            $done_once = true;
        }

        require_code('csrf_filter');
        $value .= '<input type="hidden" name="csrf_token" value="' . escape_html(generate_csrf_token()) . '" />';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_HONEYPOT_LINK($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    $honeypot_url = get_option('honeypot_url');
    if (($honeypot_url != '') && (!is_null($honeypot_url))) {
        $first_char = substr(md5(get_page_name()), 0, 1);
        $bot_phrase = get_option('honeypot_phrase');
        switch ($first_char) {
            case '0':
            case '1':
                $value = '<a rel="nofollow" href="' . escape_html($honeypot_url) . '"><' . '!-- ' . escape_html($bot_phrase) . ' --></a>';
                break;
            case '2':
            case '3':
                $value = '<a rel="nofollow" href="' . escape_html($honeypot_url) . '"><img alt="' . escape_html($bot_phrase) . '" src="' . escape_html(find_theme_image('blank')) . '" height="1" width="1" border="0" /></a>';
                break;
            case '4':
            case '5':
                $value = '<a rel="nofollow" href="' . escape_html($honeypot_url) . '" style="display: none;">' . escape_html($bot_phrase) . '</a>';
                break;
            case '6':
            case '7':
                $value = '<div style="display: none;"><a rel="nofollow" href="' . escape_html($honeypot_url) . '">' . escape_html($bot_phrase) . '</a></div>';
                break;
            case '8':
            case '9':
                $value = '<a rel="nofollow" href="' . escape_html($honeypot_url) . '"></a>';
                break;
            case 'a':
            case 'b':
                $value = '<' . '!-- <a rel="nofollow" href="' . escape_html($honeypot_url) . '">' . escape_html($bot_phrase) . '</a> -->';
                break;
            case 'c':
            case 'd':
                $value = '<div style="position: absolute; top: -250px; left: -250px;"><a rel="nofollow" href="' . escape_html($honeypot_url) . '">' . escape_html($bot_phrase) . '</a></div>';
                break;
            case 'e':
                $value = '<a rel="nofollow" href="' . escape_html($honeypot_url) . '"><span style="display: none;">' . escape_html($bot_phrase) . '</span></a>';
                break;
            case 'f':
                $value = '<a rel="nofollow" href="' . escape_html($honeypot_url) . '"><div style="height: 0px; width: 0px;"></div></a>';
                break;
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_COMMENT_COUNT($lang, $escaped, $param)
{
    $value = '';

    if (isset($param[1])) {
        static $cache_comment_count = array();
        $cache_key = $param[0] . '_' . $param[1];
        if (isset($cache_comment_count[$cache_key])) {
            $value = $cache_comment_count[$cache_key];
        } else {
            if (get_option('is_on_comments') == '1') {
                $count = 0;
                $_comments = $GLOBALS['FORUM_DRIVER']->get_forum_topic_posts($GLOBALS['FORUM_DRIVER']->find_topic_id_for_topic_identifier(get_option('comments_forum_name'), $cache_key, do_lang('COMMENT')), $count, 0, 0, false);
                if (($count != 0) || (!array_key_exists(2, $param)) || ($param[2] == '0')) {
                    if (is_array($_comments)) {
                        $_value = do_lang_tempcode('_COMMENTS', escape_html(integer_format($count)));
                    } else {
                        $_value = do_lang_tempcode('_COMMENTS', escape_html(integer_format(0)));
                    }
                    $value = $_value->evaluate();
                }
            } else {
                $value = do_lang('VIEW');
            }
            $cache_comment_count[$cache_key] = $value;
        }
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_SELF_URL($lang, $escaped, $param)
{
    $extra_params = null;
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[3])) {
        $extra_params = array();
        $i = 3;
        while (isset($param[$i])) {
            $bits = explode('=', $param[$i], 2);
            if (count($bits) == 2) {
                if ($bits[1] == '<null>') {
                    $bits[1] = null;
                }
                $extra_params[$bits[0]] = $bits[1];
            }
            $i++;
        }
    }
    $root_if_posted = (isset($param[0])) && ($param[0] == '1');
    $posted_too = (isset($param[1])) && ($param[1] == '1');
    $avoid_remap = (isset($param[2])) && ($param[2] == '1');
    $value = get_self_url(true, $root_if_posted, $extra_params, $posted_too, $avoid_remap);

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_REVIEW_STATUS($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[1])) {
        if (addon_installed('content_reviews')) {
            require_code('content_reviews');
            $value = show_content_reviews($param[0], $param[1], array_key_exists(2, $param) ? intval($param[2]) : 0);
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv__POSTED($lang, $escaped, $param)
{
    return (cms_srv('REQUEST_METHOD') == 'POST') ? '1' : '0';
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_EXTEND_URL($lang, $escaped, $param)
{
    $value = isset($param[0]) ? $param[0] : '';
    $append = isset($param[1]) ? $param[1] : '';
    extend_url($value, $append);

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_ENSURE_PROTOCOL_SUITABILITY($lang, $escaped, $param)
{
    $value = ensure_protocol_suitability(isset($param[0]) ? $param[0] : '');

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_LOGIN_LABEL($lang, $escaped, $param)
{
    switch (get_option('one_per_email_address')) {
        case '0':
            $value = do_lang('USERNAME');
            break;

        case '1':
            $value = '<span class="must_show_together">' . do_lang('USERNAME') . '/' . do_lang('EMAIL_ADDRESS') . '</span>';
            break;

        case '2':
            $value = do_lang('EMAIL_ADDRESS');
            break;
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_MOBILE($lang, $escaped, $param)
{
    $value = is_mobile(null, isset($param[0]) ? ($param[0] == '1') : false) ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_BASE_URL($lang, $escaped, $param)
{
    $value = get_base_url(isset($param[0]) ? ($param[0] == '1') : null);

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_CONFIG_OPTION($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        if ($GLOBALS['IN_MINIKERNEL_VERSION']) { // Installer, likely executing global.js. We need a saner default for JavaScript
            $value = '0';
        } else {
            $value = get_option($param[0], array_key_exists(1, $param) && $param[1] == '1');
            if ($value === null) {
                $value = '';
            }
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_INLINE_STATS($lang, $escaped, $param)
{
    $value = (get_option('show_inline_stats') == '1') ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_ADDON_INSTALLED($lang, $escaped, $param)
{
    $value = '';

    if ((isset($param[0])) && (!running_script('install'))) {
        $value = (addon_installed(trim($param[0]), (isset($param[1])) && ($param[1] == '1'))) ? '1' : '0';
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_LANG($lang, $escaped, $param)
{
    $value = user_lang();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_CNS($lang, $escaped, $param)
{
    $value = (get_forum_type() == 'cns') ? '1' : '0';

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_STRIP_HTML($lang, $escaped, $param)
{
    $value = strip_html($param[0]);

    if ($GLOBALS['XSS_DETECT'] && ocp_is_escaped($param[0])) {
        ocp_mark_as_escaped($value);
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_LENGTH($lang, $escaped, $param)
{
    $value = '0';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $value = strval(cms_mb_strlen($param[0]));
    }

    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_COPYRIGHT($lang, $escaped, $param)
{
    $value = get_option('copyright');
    if (strpos($value, '$') !== false) {
        $value = str_replace('$CURRENT_YEAR=', '', $value); // Update-on-posting, does nothing dynamically
        $value = str_replace('$CURRENT_YEAR', date('Y'), $value); // Always updated
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_BRAND_NAME($lang, $escaped, $param)
{
    $value = brand_name();

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_IMG_INLINE($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        if ((isset($GLOBALS['SITE_DB'])) && (function_exists('find_theme_image')) && (!$GLOBALS['IN_MINIKERNEL_VERSION']) && ($GLOBALS['FORUM_DRIVER'] !== null)) {
            $value = find_theme_image($param[0], true, true, (isset($param[2]) && $param[2] != '') ? $param[2] : null, null, ((isset($param[1])) && ($param[1] == '1')) ? $GLOBALS['FORUM_DB'] : $GLOBALS['SITE_DB']);
        } else {
            $value = 'themes/default/images/' . $param[0] . '.png';
        }
        if ($value != '') {
            $file_path = ((substr($value, 0, 22) == 'themes/default/images/') ? get_file_base() : get_custom_file_base()) . '/' . $value;
            $file_size = @filesize($file_path);
            if (($file_size !== false) && (floatval($file_size) * 1.4 < 32768.0 - 100.0)) { /* 1.4 represents inflation ratio for base64 encoding */
                require_code('mime_types');
                $value = 'data:' . get_mime_type(get_file_extension($file_path), false) . ';base64,' . base64_encode(file_get_contents($file_path));
            } else {
                return ecv_IMG($lang, $escaped, $param); // LEGACY: IE8
            }
        } else {
            return ecv_IMG($lang, $escaped, $param);
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_THEME_WIZARD_COLOR($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[2])) {
        global $TEMPCODE_SETGET;
        $TEMPCODE_SETGET[$param[1]] = $param[0];
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_SMART_LINK_STRIP($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[1])) {
        $value = $param[0];

        if ((!has_no_forum()) && ($GLOBALS['FORUM_DRIVER']->get_post_count(intval($param[1])) < 1)) {
            $value = cms_strip_tags($value, '<a>', false);

            if ($value != $param[0]) {
                $value .= '<br /><em>' . do_lang('LINKS_STRIPPED') . '</em>';
            }
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_ROUND($lang, $escaped, $param)
{
    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[0])) {
        $amount = isset($param[1]) ? intval($param[1]) : 0;
        if ($amount > 0) {
            $value = float_format(floatval($param[0]), $amount);
        } else {
            $value = strval(intval(round(floatval($param[0]), $amount)));
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_RATING($lang, $escaped, $param)
{
    $value = mixed();

    $value = '';
    if ($GLOBALS['XSS_DETECT']) {
        ocp_mark_as_escaped($value);
    }

    if (isset($param[1])) {
        static $cache_rating = array();
        $cache_key = serialize($param);
        if (isset($cache_rating[$cache_key])) {
            $value = $cache_rating[$cache_key];
        } else {
            global $DISPLAYED_TITLE;

            require_code('feedback');
            $display_tpl = empty($param[5]) ? 'RATING_FORM' : $param[5];
            $rating = get_rating_simple_array(
                empty($param[3]) ? get_self_url(true) : $param[3], // content_url
                empty($param[4]) ? (is_null($DISPLAYED_TITLE) ? '' : $DISPLAYED_TITLE->evaluate()) : $param[4], // content_title
                $param[0], // content_type
                $param[1], // content_id
                'RATING_FORM', // form_tpl
                empty($param[2]) ? null : intval($param[2]) // submitter
            );
            if ($rating !== null) {
                if (empty($param[5])) {
                    $value = isset($rating['ALL_RATING_CRITERIA'][key($rating['ALL_RATING_CRITERIA'])]['RATING']) ? $rating['ALL_RATING_CRITERIA'][key($rating['ALL_RATING_CRITERIA'])]['RATING'] : '';
                } else {
                    $value = static_evaluate_tempcode(do_template($display_tpl, $rating));
                }
            }

            $cache_rating[$cache_key] = $value;
        }
    }

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}

/**
 * Evaluate a particular Tempcode symbol.
 *
 * @ignore
 *
 * @param  LANGUAGE_NAME $lang The language to evaluate this symbol in (some symbols refer to language elements).
 * @param  array $escaped Array of escaping operations.
 * @param  array $param Parameters to the symbol. For all but directive it is an array of strings. For directives it is an array of Tempcode objects. Actually there may be template-style parameters in here, as an influence of singular_bind and these may be Tempcode, but we ignore them.
 * @return string The result.
 */
function ecv_TAPATALK($lang, $escaped, $param)
{
    $value = (defined('IN_MOBIQUO') ? '1' : '0');

    if ($escaped !== array()) {
        apply_tempcode_escaping($escaped, $value);
    }
    return $value;
}
