                       // too much recursion prevents proper detection
                        // so give up
                        return array_unique($expected);
                    }
                    $yyruleno = $yyact - self::YYNSTATE;
                    $this->yyidx -= self::$yyRuleInfo[ $yyruleno ][ 1 ];
                    $nextstate = $this->yy_find_reduce_action(
                        $this->yystack[ $this->yyidx ]->stateno,
                        self::$yyRuleInfo[ $yyruleno ][ 0 ]
                    );
                    if (isset(self::$yyExpectedTokens[ $nextstate ])) {
                        $expected = array_merge($expected, self::$yyExpectedTokens[ $nextstate ]);
                        if (isset($res4[ $nextstate ][ $token ])) {
                            if ($res4[ $nextstate ][ $token ]) {
                                $this->yyidx = $yyidx;
                                $this->yystack = $stack;
                                return array_unique($expected);
                            }
                        } else {
                            if ($res4[ $nextstate ][ $token ] =
                                in_array($token, self::$yyExpectedTokens[ $nextstate ], true)) {
                                $this->yyidx = $yyidx;
                                $this->yystack = $stack;
                                return array_unique($expected);
                            }
                        }
                    }
                    if ($nextstate < self::YYNSTATE) {
                        // we need to shift a non-terminal
                        $this->yyidx++;
                        $x = new TPC_yyStackEntry;
                        $x->stateno = $nextstate;
                        $x->major = self::$yyRuleInfo[ $yyruleno ][ 0 ];
                        $this->yystack[ $this->yyidx ] = $x;
                        continue 2;
                    } elseif ($nextstate === self::YYNSTATE + self::YYNRULE + 1) {
                        $this->yyidx = $yyidx;
                        $this->yystack = $stack;
                        // the last token was just ignored, we can't accept
                        // by ignoring input, this is in essence ignoring a
                        // syntax error!
                        return array_unique($expected);
                    } elseif ($nextstate === self::YY_NO_ACTION) {
                        $this->yyidx = $yyidx;
                        $this->yystack = $stack;
                        // input accepted, but not shifted (I guess)
                        return $expected;
                    } else {
                        $yyact = $nextstate;
                    }
                } while (true);
            }
            break;
        } while (true);
        $this->yyidx = $yyidx;
        $this->yystack = $stack;
        return array_unique($expected);
    }

    public function yy_is_expected_token($token)
    {
        static $res = array();
        static $res2 = array();
        if ($token === 0) {
            return true; // 0 is not part of this
        }
        $state = $this->yystack[ $this->yyidx ]->stateno;
        if (isset($res[ $state ][ $token ])) {
            if ($res[ $state ][ $token ]) {
                return true;
            }
        } else {
            if ($res[ $state ][ $token ] = in_array($token, self::$yyExpectedTokens[ $state ], true)) {
                return true;
            }
        }
        $stack = $this->yystack;
        $yyidx = $this->yyidx;
        do {
            $yyact = $this->yy_find_shift_action($token);
            if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) {
                // reduce action
                $done = 0;
                do {
                    if ($done++ === 100) {
                        $this->yyidx = $yyidx;
                        $this->yystack = $stack;
                        // too much recursion prevents proper detection
                        // so give up
                        return true;
                    }
                    $yyruleno = $yyact - self::YYNSTATE;
                    $this->yyidx -= self::$yyRuleInfo[ $yyruleno ][ 1 ];
                    $nextstate = $this->yy_find_reduce_action(
                        $this->yystack[ $this->yyidx ]->stateno,
                        self::$yyRuleInfo[ $yyruleno ][ 0 ]
                    );
                    if (isset($res2[ $nextstate ][ $token ])) {
                        if ($res2[ $nextstate ][ $token ]) {
                            $this->yyidx = $yyidx;
                            $this->yystack = $stack;
                            return true;
                        }
                    } else {
                        if ($res2[ $nextstate ][ $token ] =
                            (isset(self::$yyExpectedTokens[ $nextstate ]) &&
                             in_array($token, self::$yyExpectedTokens[ $nextstate ], true))) {
                            $this->yyidx = $yyidx;
                            $this->yystack = $stack;
                            return true;
                        }
                    }
                    if ($nextstate < self::YYNSTATE) {
                        // we need to shift a non-terminal
                        $this->yyidx++;
                        $x = new TPC_yyStackEntry;
                        $x->stateno = $nextstate;
                        $x->major = self::$yyRuleInfo[ $yyruleno ][ 0 ];
                        $this->yystack[ $this->yyidx ] = $x;
                        continue 2;
                    } elseif ($nextstate === self::YYNSTATE + self::YYNRULE + 1) {
                        $this->yyidx = $yyidx;
                        $this->yystack = $stack;
                        if (!$token) {
                            // end of input: this is valid
                            return true;
                        }
                        // the last token was just ignored, we can't accept
                        // by ignoring input, this is in essence ignoring a
                        // syntax error!
                        return false;
                    } elseif ($nextstate === self::YY_NO_ACTION) {
                        $this->yyidx = $yyidx;
                        $this->yystack = $stack;
                        // input accepted, but not shifted (I guess)
                        return true;
                    } else {
                        $yyact = $nextstate;
                    }
                } while (true);
            }
            break;
        } while (true);
        $this->yyidx = $yyidx;
        $this->yystack = $stack;
        return true;
    }

    public function yy_find_shift_action($iLookAhead)
    {
        $stateno = $this->yystack[ $this->yyidx ]->stateno;
        /* if ($this->yyidx < 0) return self::YY_NO_ACTION;  */
        if (!isset(self::$yy_shift_ofst[ $stateno ])) {
            // no shift actions
            return self::$yy_default[ $stateno ];
        }
        $i = self::$yy_shift_ofst[ $stateno ];
        if ($i === self::YY_SHIFT_USE_DFLT) {
            return self::$yy_default[ $stateno ];
        }
        if ($iLookAhead === self::YYNOCODE) {
            return self::YY_NO_ACTION;
        }
        $i += $iLookAhead;
        if ($i < 0 || $i >= self::YY_SZ_ACTTAB ||
            self::$yy_lookahead[ $i ] != $iLookAhead) {
            if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback)
                && ($iFallback = self::$yyFallback[ $iLookAhead ]) != 0) {
                if ($this->yyTraceFILE) {
                    fwrite($this->yyTraceFILE, $this->yyTracePrompt . 'FALLBACK ' .
                                               $this->yyTokenName[ $iLookAhead ] . ' => ' .
                                               $this->yyTokenName[ $iFallback ] . "\n");
                }
                return $this->yy_find_shift_action($iFallback);
            }
            return self::$yy_default[ $stateno ];
        } else {
            return self::$yy_action[ $i ];
        }
    }

    public function yy_find_reduce_action($stateno, $iLookAhead)
    {
        /* $stateno = $this->yystack[$this->yyidx]->stateno; */
        if (!isset(self::$yy_reduce_ofst[ $stateno ])) {
            return self::$yy_default[ $stateno ];
        }
        $i = self::$yy_reduce_ofst[ $stateno ];
        if ($i === self::YY_REDUCE_USE_DFLT) {
            return self::$yy_default[ $stateno ];
        }
        if ($iLookAhead === self::YYNOCODE) {
            return self::YY_NO_ACTION;
        }
        $i += $iLookAhead;
        if ($i < 0 || $i >= self::YY_SZ_ACTTAB ||
            self::$yy_lookahead[ $i ] != $iLookAhead) {
            return self::$yy_default[ $stateno ];
        } else {
            return self::$yy_action[ $i ];
        }
    }

    public function yy_shift($yyNewState, $yyMajor, $yypMinor)
    {
        $this->yyidx++;
        if ($this->yyidx >= self::YYSTACKDEPTH) {
            $this->yyidx--;
            if ($this->yyTraceFILE) {
                fprintf($this->yyTraceFILE, "%sStack Overflow!\n", $this->yyTracePrompt);
            }
            while ($this->yyidx >= 0) {
                $this->yy_pop_parser_stack();
            }
            // line 239 "../smarty/lexer/smarty_internal_configfileparser.y"
            $this->internalError = true;
            $this->compiler->trigger_config_file_error('Stack overflow in configfile parser');
            return;
        }
        $yytos = new TPC_yyStackEntry;
        $yytos->stateno = $yyNewState;
        $yytos->major = $yyMajor;
        $yytos->minor = $yypMinor;
        $this->yystack[] = $yytos;
        if ($this->yyTraceFILE && $this->yyidx > 0) {
            fprintf(
                $this->yyTraceFILE,
                "%sShift %d\n",
                $this->yyTracePrompt,
                $yyNewState
            );
            fprintf($this->yyTraceFILE, "%sStack:", $this->yyTracePrompt);
            for ($i = 1; $i <= $this->yyidx; $i++) {
                fprintf(
                    $this->yyTraceFILE,
                    " %s",
                    $this->yyTokenName[ $this->yystack[ $i ]->major ]
                );
            }
            fwrite($this->yyTraceFILE, "\n");
        }
    }

    public function yy_r0()
    {
        $this->_retvalue = null;
    }

    public function yy_r1()
    {
        $this->add_global_vars($this->yystack[ $this->yyidx + 0 ]->minor);
        $this->_retvalue = null;
    }

    public function yy_r4()
    {
        $this->add_section_vars($this->yystack[ $this->yyidx + -3 ]->minor, $this->yystack[ $this->yyidx + 0 ]->minor);
        $this->_retvalue = null;
    }

    // line 245 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r5()
    {
        if ($this->configReadHidden) {
            $this->add_section_vars(
                $this->yystack[ $this->yyidx + -3 ]->minor,
                $this->yystack[ $this->yyidx + 0 ]->minor
            );
        }
        $this->_retvalue = null;
    }

    // line 250 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r6()
    {
        $this->_retvalue = $this->yystack[ $this->yyidx + -1 ]->minor;
    }

    // line 264 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r7()
    {
        $this->_retvalue =
            array_merge($this->yystack[ $this->yyidx + -1 ]->minor, array($this->yystack[ $this->yyidx + 0 ]->minor));
    }

    // line 269 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r8()
    {
        $this->_retvalue = array();
    }

    // line 277 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r9()
    {
        $this->_retvalue =
            array(
                'key'   => $this->yystack[ $this->yyidx + -2 ]->minor,
                'value' => $this->yystack[ $this->yyidx + 0 ]->minor
            );
    }

    // line 281 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r10()
    {
        $this->_retvalue = (float)$this->yystack[ $this->yyidx + 0 ]->minor;
    }

    // line 285 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r11()
    {
        $this->_retvalue = (int)$this->yystack[ $this->yyidx + 0 ]->minor;
    }

    // line 291 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r12()
    {
        $this->_retvalue = $this->parse_bool($this->yystack[ $this->yyidx + 0 ]->minor);
    }

    // line 296 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r13()
    {
        $this->_retvalue = self::parse_single_quoted_string($this->yystack[ $this->yyidx + 0 ]->minor);
    }

    // line 300 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r14()
    {
        $this->_retvalue = self::parse_double_quoted_string($this->yystack[ $this->yyidx + 0 ]->minor);
    }

    // line 304 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r15()
    {
        $this->_retvalue = self::parse_tripple_double_quoted_string($this->yystack[ $this->yyidx + -1 ]->minor);
    }

    // line 308 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r16()
    {
        $this->_retvalue = '';
    }

    // line 312 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_r17()
    {
        $this->_retvalue = $this->yystack[ $this->yyidx + 0 ]->minor;
    }

    // line 316 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_reduce($yyruleno)
    {
        if ($this->yyTraceFILE && $yyruleno >= 0
            && $yyruleno < count(self::$yyRuleName)) {
            fprintf(
                $this->yyTraceFILE,
                "%sReduce (%d) [%s].\n",
                $this->yyTracePrompt,
                $yyruleno,
                self::$yyRuleName[ $yyruleno ]
            );
        }
        $this->_retvalue = $yy_lefthand_side = null;
        if (isset(self::$yyReduceMap[ $yyruleno ])) {
            // call the action
            $this->_retvalue = null;
            $this->{'yy_r' . self::$yyReduceMap[ $yyruleno ]}();
            $yy_lefthand_side = $this->_retvalue;
        }
        $yygoto = self::$yyRuleInfo[ $yyruleno ][ 0 ];
        $yysize = self::$yyRuleInfo[ $yyruleno ][ 1 ];
        $this->yyidx -= $yysize;
        for ($i = $yysize; $i; $i--) {
            // pop all of the right-hand side parameters
            array_pop($this->yystack);
        }
        $yyact = $this->yy_find_reduce_action($this->yystack[ $this->yyidx ]->stateno, $yygoto);
        if ($yyact < self::YYNSTATE) {
            if (!$this->yyTraceFILE && $yysize) {
                $this->yyidx++;
                $x = new TPC_yyStackEntry;
                $x->stateno = $yyact;
                $x->major = $yygoto;
                $x->minor = $yy_lefthand_side;
                $this->yystack[ $this->yyidx ] = $x;
            } else {
                $this->yy_shift($yyact, $yygoto, $yy_lefthand_side);
            }
        } elseif ($yyact === self::YYNSTATE + self::YYNRULE + 1) {
            $this->yy_accept();
        }
    }

    // line 320 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_parse_failed()
    {
        if ($this->yyTraceFILE) {
            fprintf($this->yyTraceFILE, "%sFail!\n", $this->yyTracePrompt);
        }
        while ($this->yyidx >= 0) {
            $this->yy_pop_parser_stack();
        }
    }

    // line 324 "../smarty/lexer/smarty_internal_configfileparser.y"
    public function yy_syntax_error($yymajor, $TOKEN)
    {
        // line 232 "../smarty/lexer/smarty_internal_configfileparser.y"
        $this->internalError = true;
        $this->yymajor = $yymajor;
        $this->compiler->trigger_config_file_error();
    }

    public function yy_accept()
    {
        if ($this->yyTraceFILE) {
            fprintf($this->yyTraceFILE, "%sAccept!\n", $this->yyTracePrompt);
        }
        while ($this->yyidx >= 0) {
            $this->yy_pop_parser_stack();
        }
        // line 225 "../smarty/lexer/smarty_internal_configfileparser.y"
        $this->successful = !$this->internalError;
        $this->internalError = false;
        $this->retvalue = $this->_retvalue;
    }

    public function doParse($yymajor, $yytokenvalue)
    {
        $yyerrorhit = 0;   /* True if yymajor has invoked an error */
        if ($this->yyidx === null || $this->yyidx < 0) {
            $this->yyidx = 0;
            $this->yyerrcnt = -1;
            $x = new TPC_yyStackEntry;
            $x->stateno = 0;
            $x->major = 0;
            $this->yystack = array();
            $this->yystack[] = $x;
        }
        $yyendofinput = ($yymajor == 0);
        if ($this->yyTraceFILE) {
            fprintf(
                $this->yyTraceFILE,
                "%sInput %s\n",
                $this->yyTracePrompt,
                $this->yyTokenName[ $yymajor ]
            );
        }
        do {
            $yyact = $this->yy_find_shift_action($yymajor);
            if ($yymajor < self::YYERRORSYMBOL &&
                !$this->yy_is_expected_token($yymajor)) {
                // force a syntax error
                $yyact = self::YY_ERROR_ACTION;
            }
            if ($yyact < self::YYNSTATE) {
                $this->yy_shift($yyact, $yymajor, $yytokenvalue);
                $this->yyerrcnt--;
                if ($yyendofinput && $this->yyidx >= 0) {
                    $yymajor = 0;
                } else {
                    $yymajor = self::YYNOCODE;
                }
            } elseif ($yyact < self::YYNSTATE + self::YYNRULE) {
                $this->yy_reduce($yyact - self::YYNSTATE);
            } elseif ($yyact === self::YY_ERROR_ACTION) {
                if ($this->yyTraceFILE) {
                    fprintf(
                        $this->yyTraceFILE,
                        "%sSyntax Error!\n",
                        $this->yyTracePrompt
                    );
                }
                if (self::YYERRORSYMBOL) {
                    if ($this->yyerrcnt < 0) {
                        $this->yy_syntax_error($yymajor, $yytokenvalue);
                    }
                    $yymx = $this->yystack[ $this->yyidx ]->major;
                    if ($yymx === self::YYERRORSYMBOL || $yyerrorhit) {
                        if ($this->yyTraceFILE) {
                            fprintf(
                                $this->yyTraceFILE,
                                "%sDiscard input token %s\n",
                                $this->yyTracePrompt,
                                $this->yyTokenName[ $yymajor ]
                            );
                        }
                        $this->yy_destructor($yymajor, $yytokenvalue);
                        $yymajor = self::YYNOCODE;
                    } else {
                        while ($this->yyidx >= 0 &&
                               $yymx !== self::YYERRORSYMBOL &&
                               ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE
                        ) {
                            $this->yy_pop_parser_stack();
                        }
                        if ($this->yyidx < 0 || $yymajor == 0) {
                            $this->yy_destructor($yymajor, $yytokenvalue);
                            $this->yy_parse_failed();
                            $yymajor = self::YYNOCODE;
                        } elseif ($yymx !== self::YYERRORSYMBOL) {
                            $u2 = 0;
                            $this->yy_shift($yyact, self::YYERRORSYMBOL, $u2);
                        }
                    }
                    $this->yyerrcnt = 3;
                    $yyerrorhit = 1;
                } else {
                    if ($this->yyerrcnt <= 0) {
                        $this->yy_syntax_error($yymajor, $yytokenvalue);
                    }
                    $this->yyerrcnt = 3;
                    $this->yy_destructor($yymajor, $yytokenvalue);
                    if ($yyendofinput) {
                        $this->yy_parse_failed();
                    }
                    $yymajor = self::YYNOCODE;
                }
            } else {
                $this->yy_accept();
                $yymajor = self::YYNOCODE;
            }
        } while ($yymajor !== self::YYNOCODE && $this->yyidx >= 0);
    }

    /**
     * parse optional boolean keywords
     *
     * @param string $str
     *
     * @return bool
     */
    private function parse_bool($str)
    {
        $str = strtolower($str);
        if (in_array($str, array('on', 'yes', 'true'))) {
            $res = true;
        } else {
            $res = false;
        }
        return $res;
    }

    /**
     * set a config variable in target array
     *
     * @param array $var
     * @param array $target_array
     */
    private function set_var(array $var, array &$target_array)
    {
        $key = $var[ 'key' ];
        $value = $var[ 'value' ];
        if ($this->configOverwrite || !isset($target_array[ 'vars' ][ $key ])) {
            $target_array[ 'vars' ][ $key ] = $value;
        } else {
            settype($target_array[ 'vars' ][ $key ], 'array');
            $target_array[ 'vars' ][ $key ][] = $value;
        }
    }

    /**
     * add config variable to global vars
     *
     * @param array $vars
     */
    private function add_global_vars(array $vars)
    {
        if (!isset($this->compiler->config_data[ 'vars' ])) {
            $this->compiler->config_data[ 'vars' ] = array();
        }
        foreach ($vars as $var) {
            $this->set_var($var, $this->compiler->config_data);
        }
    }

    /**
     * add config variable to section
     *
     * @param string $section_name
     * @param array  $vars
     */
    private function add_section_vars($section_name, array $vars)
    {
        if (!isset($this->compiler->config_data[ 'sections' ][ $section_name ][ 'vars' ])) {
            $this->compiler->config_data[ 'sections' ][ $section_name ][ 'vars' ] = array();
        }
        foreach ($vars as $var) {
            $this->set_var($var, $this->compiler->config_data[ 'sections' ][ $section_name ]);
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                <?php
/**
 * Smarty Internal Plugin Smarty Template Compiler Base
 * This file contains the basic classes and methods for compiling Smarty templates with lexer/parser
 *
 * @package    Smarty
 * @subpackage Compiler
 * @author     Uwe Tews
 */

/**
 * Main abstract compiler class
 *
 * @package    Smarty
 * @subpackage Compiler
 *
 * @property Smarty_Internal_SmartyTemplateCompiler $prefixCompiledCode  = ''
 * @property Smarty_Internal_SmartyTemplateCompiler $postfixCompiledCode = ''
 * @method   registerPostCompileCallback($callback, $parameter = array(), $key = null, $replace = false)
 * @method   unregisterPostCompileCallback($key)
 */
abstract class Smarty_Internal_TemplateCompilerBase
{
    /**
     * compile tag objects cache
     *
     * @var array
     */
    public static $_tag_objects = array();

    /**
     * counter for prefix variable number
     *
     * @var int
     */
    public static $prefixVariableNumber = 0;

    /**
     * Smarty object
     *
     * @var Smarty
     */
    public $smarty = null;

    /**
     * Parser object
     *
     * @var Smarty_Internal_Templateparser
     */
    public $parser = null;

    /**
     * hash for nocache sections
     *
     * @var mixed
     */
    public $nocache_hash = null;

    /**
     * suppress generation of nocache code
     *
     * @var bool
     */
    public $suppressNocacheProcessing = false;

    /**
     * caching enabled (copied from template object)
     *
     * @var int
     */
    public $caching = 0;

    /**
     * tag stack
     *
     * @var array
     */
    public $_tag_stack = array();

    /**
     * tag stack count
     *
     * @var array
     */
    public $_tag_stack_count = array();

    /**
     * Plugins used by template
     *
     * @var array
     */
    public $required_plugins = array('compiled' => array(), 'nocache' => array());

    /**
     * Required plugins stack
     *
     * @var array
     */
    public $required_plugins_stack = array();

    /**
     * current template
     *
     * @var Smarty_Internal_Template
     */
    public $template = null;

    /**
     * merged included sub template data
     *
     * @var array
     */
    public $mergedSubTemplatesData = array();

    /**
     * merged sub template code
     *
     * @var array
     */
    public $mergedSubTemplatesCode = array();

    /**
     * collected template properties during compilation
     *
     * @var array
     */
    public $templateProperties = array();

    /**
     * source line offset for error messages
     *
     * @var int
     */
    public $trace_line_offset = 0;

    /**
     * trace uid
     *
     * @var string
     */
    public $trace_uid = '';

    /**
     * trace file path
     *
     * @var string
     */
    public $trace_filepath = '';

    /**
     * stack for tracing file and line of nested {block} tags
     *
     * @var array
     */
    public $trace_stack = array();

    /**
     * plugins loaded by default plugin handler
     *
     * @var array
     */
    public $default_handler_plugins = array();

    /**
     * saved preprocessed modifier list
     *
     * @var mixed
     */
    public $default_modifier_list = null;

    /**
     * force compilation of complete template as nocache
     *
     * @var boolean
     */
    public $forceNocache = false;

    /**
     * flag if compiled template file shall we written
     *
     * @var bool
     */
    public $write_compiled_code = true;

    /**
     * Template functions
     *
     * @var array
     */
    public $tpl_function = array();

    /**
     * called sub functions from template function
     *
     * @var array
     */
    public $called_functions = array();

    /**
     * compiled template or block function code
     *
     * @var string
     */
    public $blockOrFunctionCode = '';

    /**
     * php_handling setting either from Smarty or security
     *
     * @var int
     */
    public $php_handling = 0;

    /**
     * flags for used modifier plugins
     *
     * @var array
     */
    public $modifier_plugins = array();

    /**
     * type of already compiled modifier
     *
     * @var array
     */
    public $known_modifier_type = array();

    /**
     * parent compiler object for merged subtemplates and template functions
     *
     * @var Smarty_Internal_TemplateCompilerBase
     */
    public $parent_compiler = null;

    /**
     * Flag true when compiling nocache section
     *
     * @var bool
     */
    public $nocache = false;

    /**
     * Flag true when tag is compiled as nocache
     *
     * @var bool
     */
    public $tag_nocache = false;

    /**
     * Compiled tag prefix code
     *
     * @var array
     */
    public $prefix_code = array();

    /**
     * used prefix variables by current compiled tag
     *
     * @var array
     */
    public $usedPrefixVariables = array();

    /**
     * Prefix code  stack
     *
     * @var array
     */
    public $prefixCodeStack = array();

    /**
     * Tag has compiled code
     *
     * @var bool
     */
    public $has_code = false;

    /**
     * A variable string was compiled
     *
     * @var bool
     */
    public $has_variable_string = false;

    /**
     * Stack for {setfilter} {/setfilter}
     *
     * @var array
     */
    public $variable_filter_stack = array();

    /**
     * variable filters for {setfilter} {/setfilter}
     *
     * @var array
     */
    public $variable_filters = array();

    /**
     * Nesting count of looping tags like {foreach}, {for}, {section}, {while}
     *
     * @var int
     */
    public $loopNesting = 0;

    /**
     * Strip preg pattern
     *
     * @var string
     */
    public $stripRegEx = '![\t ]*[\r\n]+[\t ]*!';

    /**
     * plugin search order
     *
     * @var array
     */
    public $plugin_search_order = array(
        'function',
        'block',
        'compiler',
        'class'
    );

    /**
     * General storage area for tag compiler plugins
     *
     * @var array
     */
    public $_cache = array();

    /**
     * Lexer preg pattern for left delimiter
     *
     * @var string
     */
    private $ldelPreg = '[{]';

    /**
     * Lexer preg pattern for right delimiter
     *
     * @var string
     */
    private $rdelPreg = '[}]';

    /**
     * Length of right delimiter
     *
     * @var int
     */
    private $rdelLength = 0;

    /**
     * Length of left delimiter
     *
     * @var int
     */
    private $ldelLength = 0;

    /**
     * Lexer preg pattern for user literals
     *
     * @var string
     */
    private $literalPreg = '';

    /**
     * Initialize compiler
     *
     * @param Smarty $smarty global instance
     */
    public function __construct(Smarty $smarty)
    {
        $this->smarty = $smarty;
        $this->nocache_hash = str_replace(
            array(
                '.',
                ','
            ),
            '_',
            uniqid(mt_rand(), true)
        );
    }

    /**
     * Method to compile a Smarty template
     *
     * @param Smarty_Internal_Template                  $template template object to compile
     * @param bool                                      $nocache  true is shall be compiled in nocache mode
     * @param null|Smarty_Internal_TemplateCompilerBase $parent_compiler
     *
     * @return bool true if compiling succeeded, false if it failed
     * @throws \Exception
     */
    public function compileTemplate(
        Smarty_Internal_Template $template,
        $nocache = null,
        Smarty_Internal_TemplateCompilerBase $parent_compiler = null
    ) {
        // get code frame of compiled template
        $_compiled_code = $template->smarty->ext->_codeFrame->create(
            $template,
            $this->compileTemplateSource(
                $template,
                $nocache,
                $parent_compiler
            ),
            $this->postFilter($this->blockOrFunctionCode) .
            join('', $this->mergedSubTemplatesCode),
            false,
            $this
        );
        return $_compiled_code;
    }

    /**
     * Compile template source and run optional post filter
     *
     * @param \Smarty_Internal_Template             $template
     * @param null|bool                             $nocache flag if template must be compiled in nocache mode
     * @param \Smarty_Internal_TemplateCompilerBase $parent_compiler
     *
     * @return string
     * @throws \Exception
     */
    public function compileTemplateSource(
        Smarty_Internal_Template $template,
        $nocache = null,
        Smarty_Internal_TemplateCompilerBase $parent_compiler = null
    ) {
        try {
            // save template object in compiler class
            $this->template = $template;
            if (property_exists($this->template->smarty, 'plugin_search_order')) {
                $this->plugin_search_order = $this->template->smarty->plugin_search_order;
            }
            if ($this->smarty->debugging) {
                if (!isset($this->smarty->_debug)) {
                    $this->smarty->_debug = new Smarty_Internal_Debug();
                }
                $this->smarty->_debug->start_compile($this->template);
            }
            if (isset($this->template->smarty->security_policy)) {
                $this->php_handling = $this->template->smarty->security_policy->php_handling;
            } else {
                $this->php_handling = $this->template->smarty->php_handling;
            }
            $this->parent_compiler = $parent_compiler ? $parent_compiler : $this;
            $nocache = isset($nocache) ? $nocache : false;
            if (empty($template->compiled->nocache_hash)) {
                $template->compiled->nocache_hash = $this->nocache_hash;
            } else {
                $this->nocache_hash = $template->compiled->nocache_hash;
            }
            $this->caching = $template->caching;
            // flag for nocache sections
            $this->nocache = $nocache;
            $this->tag_nocache = false;
            // reset has nocache code flag
            $this->template->compiled->has_nocache_code = false;
            $this->has_variable_string = false;
            $this->prefix_code = array();
            // add file dependency
            if ($this->smarty->merge_compiled_includes || $this->template->source->handler->checkTimestamps()) {
                $this->parent_compiler->template->compiled->file_dependency[ $this->template->source->uid ] =
                    array(
                        $this->template->source->filepath,
                        $this->template->source->getTimeStamp(),
                        $this->template->source->type,
                    );
            }
            $this->smarty->_current_file = $this->template->source->filepath;
            // get template source
            if (!empty($this->template->source->components)) {
                // we have array of inheritance templates by extends: resource
                // generate corresponding source code sequence
                $_content =
                    Smarty_Internal_Compile_Extends::extendsSourceArrayCode($this->template);
            } else {
                // get template source
                $_content = $this->template->source->getContent();
            }
            $_compiled_code = $this->postFilter($this->doCompile($this->preFilter($_content), true));
            if (!empty($this->required_plugins[ 'compiled' ]) || !empty($this->required_plugins[ 'nocache' ])) {
                $_compiled_code = '<?php ' . $this->compileRequiredPlugins() . "?>\n" . $_compiled_code;
            }
        } catch (Exception $e) {
            if ($this->smarty->debugging) {
                $this->smarty->_debug->end_compile($this->template);
            }
            $this->_tag_stack = array();
            // free memory
            $this->parent_compiler = null;
            $this->template = null;
            $this->parser = null;
            throw $e;
        }
        if ($this->smarty->debugging) {
            $this->smarty->_debug->end_compile($this->template);
        }
        $this->parent_compiler = null;
        $this->parser = null;
        return $_compiled_code;
    }

    /**
     * Optionally process compiled code by post filter
     *
     * @param string $code compiled code
     *
     * @return string
     * @throws \SmartyException
     */
    public function postFilter($code)
    {
        // run post filter if on code
        if (!empty($code)
            && (isset($this->smarty->autoload_filters[ 'post' ]) || isset($this->smarty->registered_filters[ 'post' ]))
        ) {
            return $this->smarty->ext->_filterHandler->runFilter('post', $code, $this->template);
        } else {
            return $code;
        }
    }

    /**
     * Run optional prefilter
     *
     * @param string $_content template source
     *
     * @return string
     * @throws \SmartyException
     */
    public function preFilter($_content)
    {
        // run pre filter if required
        if ($_content !== ''
            && ((isset($this->smarty->autoload_filters[ 'pre' ]) || isset($this->smarty->registered_filters[ 'pre' ])))
        ) {
            return $this->smarty->ext->_filterHandler->runFilter('pre', $_content, $this->template);
        } else {
            return $_content;
        }
    }

    /**
     * Compile Tag
     * This is a call back from the lexer/parser
     *
     * Save current prefix code
     * Compile tag
     * Merge tag prefix code with saved one
     * (required nested tags in attributes)
     *
     * @param string $tag       tag name
     * @param array  $args      array with tag attributes
     * @param array  $parameter array with compilation parameter
     *
     * @throws SmartyCompilerException
     * @throws SmartyException
     * @return string compiled code
     */
    public function compileTag($tag, $args, $parameter = array())
    {
        $this->prefixCodeStack[] = $this->prefix_code;
        $this->prefix_code = array();
        $result = $this->compileTag2($tag, $args, $parameter);
        $this->prefix_code = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));
        return $result;
    }

    /**
     * compile variable
     *
     * @param string $variable
     *
     * @return string
     */
    public function compileVariable($variable)
    {
        if (!strpos($variable, '(')) {
            // not a variable variable
            $var = trim($variable, '\'');
            $this->tag_nocache = $this->tag_nocache |
                                 $this->template->ext->getTemplateVars->_getVariable(
                                     $this->template,
                                     $var,
                                     null,
                                     true,
                                     false
                                 )->nocache;
            // todo $this->template->compiled->properties['variables'][$var] = $this->tag_nocache | $this->nocache;
        }
        return '$_smarty_tpl->tpl_vars[' . $variable . ']->value';
    }

    /**
     * compile config variable
     *
     * @param string $variable
     *
     * @return string
     */
    public function compileConfigVariable($variable)
    {
        // return '$_smarty_tpl->config_vars[' . $variable . ']';
        return '$_smarty_tpl->smarty->ext->configLoad->_getConfigVariable($_smarty_tpl, ' . $variable . ')';
    }

    /**
     * compile PHP function call
     *
     * @param string $name
     * @param array  $parameter
     *
     * @return string
     * @throws \SmartyCompilerException
     */
    public function compilePHPFunctionCall($name, $parameter)
    {
        if (!$this->smarty->security_policy || $this->smarty->security_policy->isTrustedPhpFunction($name, $this)) {
            if (strcasecmp($name, 'isset') === 0 || strcasecmp($name, 'empty') === 0
                || strcasecmp($name, 'array') === 0 || is_callable($name)
            ) {
                $func_name = strtolower($name);

                if ($func_name === 'isset') {
                    if (count($parameter) === 0) {
                        $this->trigger_template_error('Illegal number of parameter in "isset()"');
                    }

	                $pa = array();
	                foreach ($parameter as $p) {
		                $pa[] = $this->syntaxMatchesVariable($p) ? 'isset(' . $p . ')' : '(' . $p . ' !== null )';
	                }
	                return '(' . implode(' && ', $pa) . ')';

                } elseif (in_array(
                    $func_name,
                    array(
                        'empty',
                        'reset',
                        'current',
                        'end',
                        'prev',
                        'next'
                    )
                )
                ) {
                    if (count($parameter) !== 1) {
                        $this->trigger_template_error("Illegal number of parameter in '{$func_name()}'");
                    }
                    if ($func_name === 'empty') {
                        if (!$this->syntaxMatchesVariable($parameter[0]) && version_compare(PHP_VERSION, '5.5.0', '<')) {
                            return '(' . $parameter[ 0 ] . ' === false )';
                        } else {
                            return $func_name . '(' .
                                   str_replace("')->value", "',null,true,false)->value", $parameter[ 0 ]) . ')';
                        }
                    } else {
                        return $func_name . '(' . $parameter[ 0 ] . ')';
                    }
                } else {
                    return $name . '(' . implode(',', $parameter) . ')';
                }
            } else {
                $this->trigger_template_error("unknown function '{$name}'");
            }
        }
    }

	/**
	 * Determines whether the passed string represents a valid (PHP) variable.
	 * This is important, because `isset()` only works on variables and `empty()` can only be passed
	 * a variable prior to php5.5
	 * @param $string
	 * @return bool
	 */
	private function syntaxMatchesVariable($string) {
    	static $regex_pattern = '/^\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*((->)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*|\[.*]*\])*$/';
    	return 1 === preg_match($regex_pattern, trim($string));
    }

    /**
     * This method is called from parser to process a text content section if strip is enabled
     * - remove text from inheritance child templates as they may generate output
     *
     * @param string $text
     *
     * @return string
     */
    public function processText($text)
    {

        if (strpos($text, '<') === false) {
        	return preg_replace($this->stripRegEx, '', $text);
        }

	    $store = array();
	    $_store = 0;

        // capture html elements not to be messed with
        $_offset = 0;
        if (preg_match_all(
            '#(<script[^>]*>.*?</script[^>]*>)|(<textarea[^>]*>.*?</textarea[^>]*>)|(<pre[^>]*>.*?</pre[^>]*>)#is',
            $text,
            $matches,
            PREG_OFFSET_CAPTURE | PREG_SET_ORDER
        )
        ) {
            foreach ($matches as $match) {
                $store[] = $match[ 0 ][ 0 ];
                $_length = strlen($match[ 0 ][ 0 ]);
                $replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
                $text = substr_replace($text, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);
                $_offset += $_length - strlen($replace);
                $_store++;
            }
        }
        $expressions = array(// replace multiple spaces between tags by a single space
                             '#(:SMARTY@!@|>)[\040\011]+(?=@!@SMARTY:|<)#s'                            => '\1 \2',
                             // remove newline between tags
                             '#(:SMARTY@!@|>)[\040\011]*[\n]\s*(?=@!@SMARTY:|<)#s'                     => '\1\2',
                             // remove multiple spaces between attributes (but not in attribute values!)
                             '#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5',
                             '#>[\040\011]+$#Ss'                                                       => '> ',
                             '#>[\040\011]*[\n]\s*$#Ss'                                                => '>',
                             $this->stripRegEx                                                         => '',
        );
        $text = preg_replace(array_keys($expressions), array_values($expressions), $text);
        $_offset = 0;
        if (preg_match_all(
            '#@!@SMARTY:([0-9]+):SMARTY@!@#is',
            $text,
            $matches,
            PREG_OFFSET_CAPTURE | PREG_SET_ORDER
        )
        ) {
            foreach ($matches as $match) {
                $_length = strlen($match[ 0 ][ 0 ]);
                $replace = $store[ $match[ 1 ][ 0 ] ];
                $text = substr_replace($text, $replace, $match[ 0 ][ 1 ] + $_offset, $_length);
                $_offset += strlen($replace) - $_length;
                $_store++;
            }
        }
        return $text;
    }

    /**
     * lazy loads internal compile plugin for tag and calls the compile method
     * compile objects cached for reuse.
     * class name format:  Smarty_Internal_Compile_TagName
     * plugin filename format: Smarty_Internal_TagName.php
     *
     * @param string $tag    tag name
     * @param array  $args   list of tag attributes
     * @param mixed  $param1 optional parameter
     * @param mixed  $param2 optional parameter
     * @param mixed  $param3 optional parameter
     *
     * @return bool|string compiled code or false
     * @throws \SmartyCompilerException
     */
    public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)
    {
        /* @var Smarty_Internal_CompileBase $tagCompiler */
        $tagCompiler = $this->getTagCompiler($tag);
        // compile this tag
        return $tagCompiler === false ? false : $tagCompiler->compile($args, $this, $param1, $param2, $param3);
    }

    /**
     * lazy loads internal compile plugin for tag compile objects cached for reuse.
     *
     * class name format:  Smarty_Internal_Compile_TagName
     * plugin filename format: Smarty_Internal_TagName.php
     *
     * @param string $tag tag name
     *
     * @return bool|\Smarty_Internal_CompileBase tag compiler object or false if not found
     */
    public function getTagCompiler($tag)
    {
        // re-use object if already exists
        if (!isset(self::$_tag_objects[ $tag ])) {
            // lazy load internal compiler plugin
            $_tag = explode('_', $tag);
            $_tag = array_map('ucfirst', $_tag);
            $class_name = 'Smarty_Internal_Compile_' . implode('_', $_tag);
            if (class_exists($class_name)
                && (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))
            ) {
                self::$_tag_objects[ $tag ] = new $class_name;
            } else {
                self::$_tag_objects[ $tag ] = false;
            }
        }
        return self::$_tag_objects[ $tag ];
    }

    /**
     * Check for plugins and return function name
     *
     * @param        $plugin_name
     * @param string $plugin_type type of plugin
     *
     * @return string call name of function
     * @throws \SmartyException
     */
    public function getPlugin($plugin_name, $plugin_type)
    {
        $function = null;
        if ($this->caching && ($this->nocache || $this->tag_nocache)) {
            if (isset($this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {
                $function =
                    $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];
            } elseif (isset($this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {
                $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ] =
                    $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ];
                $function =
                    $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];
            }
        } else {
            if (isset($this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {
                $function =
                    $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];
            } elseif (isset($this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {
                $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ] =
                    $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ];
                $function =
                    $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];
            }
        }
        if (isset($function)) {
            if ($plugin_type === 'modifier') {
                $this->modifier_plugins[ $plugin_name ] = true;
            }
            return $function;
        }
        // loop through plugin dirs and find the plugin
        $function = 'smarty_' . $plugin_type . '_' . $plugin_name;
        $file = $this->smarty->loadPlugin($function, false);
        if (is_string($file)) {
            if ($this->caching && ($this->nocache || $this->tag_nocache)) {
                $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'file' ] =
                    $file;
                $this->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ] =
                    $function;
            } else {
                $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'file' ] =
                    $file;
                $this->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ] =
                    $function;
            }
            if ($plugin_type === 'modifier') {
                $this->modifier_plugins[ $plugin_name ] = true;
            }
            return $function;
        }
        if (is_callable($function)) {
            // plugin function is defined in the script
            return $function;
        }
        return false;
    }

    /**
     * Check for plugins by default plugin handler
     *
     * @param string $tag         name of tag
     * @param string $plugin_type type of plugin
     *
     * @return bool true if found
     * @throws \SmartyCompilerException
     */
    public function getPluginFromDefaultHandler($tag, $plugin_type)
    {
        $callback = null;
        $script = null;
        $cacheable = true;
        $result = call_user_func_array(
            $this->smarty->default_plugin_handler_func,
            array(
                $tag,
                $plugin_type,
                $this->template,
                &$callback,
                &$script,
                &$cacheable,
            )
        );
        if ($result) {
            $this->tag_nocache = $this->tag_nocache || !$cacheable;
            if ($script !== null) {
                if (is_file($script)) {
                    if ($this->caching && ($this->nocache || $this->tag_nocache)) {
                        $this->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'file' ] =
                            $script;
                        $this->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'function' ] =
                            $callback;
                    } else {
                        $this->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'file' ] =
                            $script;
                        $this->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'function' ] =
                            $callback;
                    }
                    include_once $script;
                } else {
                    $this->trigger_template_error("Default plugin handler: Returned script file '{$script}' for '{$tag}' not found");
                }
            }
            if (is_callable($callback)) {
                $this->default_handler_plugins[ $plugin_type ][ $tag ] = array(
                    $callback,
                    true,
                    array()
                );
                return true;
            } else {
                $this->trigger_template_error("Default plugin handler: Returned callback for '{$tag}' not callable");
            }
        }
        return false;
    }

    /**
     * Append code segments and remove unneeded ?> <?php transitions
     *
     * @param string $left
     * @param string $right
     *
     * @return string
     */
    public function appendCode($left, $right)
    {
        if (preg_match('/\s*\?>\s?$/D', $left) && preg_match('/^<\?php\s+/', $right)) {
            $left = preg_replace('/\s*\?>\s?$/D', "\n", $left);
            $left .= preg_replace('/^<\?php\s+/', '', $right);
        } else {
            $left .= $right;
        }
        return $left;
    }

    /**
     * Inject inline code for nocache template sections
     * This method gets the content of each template element from the parser.
     * If the content is compiled code and it should be not cached the code is injected
     * into the rendered output.
     *
     * @param string  $content content of template element
     * @param boolean $is_code true if content is compiled code
     *
     * @return string  content
     */
    public function processNocacheCode($content, $is_code)
    {
        // If the template is not evaluated and we have a nocache section and or a nocache tag
        if ($is_code && !empty($content)) {
            // generate replacement code
            if ((!($this->template->source->handler->recompiled) || $this->forceNocache) && $this->caching
                && !$this->suppressNocacheProcessing && ($this->nocache || $this->tag_nocache)
            ) {
                $this->template->compiled->has_nocache_code = true;
                $_output = addcslashes($content, '\'\\');
                $_output = str_replace('^#^', '\'', $_output);
                $_output =
                    "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/{$_output}/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n";
                // make sure we include modifier plugins for nocache code
                foreach ($this->modifier_plugins as $plugin_name => $dummy) {
                    if (isset($this->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ])) {
                        $this->required_plugins[ 'nocache' ][ $plugin_name ][ 'modifier' ] =
                            $this->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ];
                    }
                }
            } else {
                $_output = $content;
            }
        } else {
            $_output = $content;
        }
        $this->modifier_plugins = array();
        $this->suppressNocacheProcessing = false;
        $this->tag_nocache = false;
        return $_output;
    }

    /**
     * Get Id
     *
     * @param string $input
     *
     * @return bool|string
     */
    public function getId($input)
    {
        if (preg_match('~^([\'"]*)([0-9]*[a-zA-Z_]\w*)\1$~', $input, $match)) {
            return $match[ 2 ];
        }
        return false;
    }

    /**
     * Get variable name from string
     *
     * @param string $input
     *
     * @return bool|string
     */
    public function getVariableName($input)
    {
        if (preg_match('~^[$]_smarty_tpl->tpl_vars\[[\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*\]->value$~', $input, $match)) {
            return $match[ 1 ];
        }
        return false;
    }

    /**
     * Set nocache flag in variable or create new variable
     *
     * @param string $varName
     */
    public function setNocacheInVariable($varName)
    {
        // create nocache var to make it know for further compiling
        if ($_var = $this->getId($varName)) {
            if (isset($this->template->tpl_vars[ $_var ])) {
                $this->template->tpl_vars[ $_var ] = clone $this->template->tpl_vars[ $_var ];
                $this->template->tpl_vars[ $_var ]->nocache = true;
            } else {
                $this->template->tpl_vars[ $_var ] = new Smarty_Variable(null, true);
            }
        }
    }

    /**
     * @param array $_attr tag attributes
     * @param array $validScopes
     *
     * @return int|string
     * @throws \SmartyCompilerException
     */
    public function convertScope($_attr, $validScopes)
    {
        $_scope = 0;
        if (isset($_attr[ 'scope' ])) {
            $_scopeName = trim($_attr[ 'scope' ], '\'"');
            if (is_numeric($_scopeName) && in_array($_scopeName, $validScopes)) {
                $_scope = $_scopeName;
            } elseif (is_string($_scopeName)) {
                $_scopeName = trim($_scopeName, '\'"');
                $_scope = isset($validScopes[ $_scopeName ]) ? $validScopes[ $_scopeName ] : false;
            } else {
                $_scope = false;
            }
            if ($_scope === false) {
                $err = var_export($_scopeName, true);
                $this->trigger_template_error("illegal value '{$err}' for \"scope\" attribute", null, true);
            }
        }
        return $_scope;
    }

    /**
     * Generate nocache code string
     *
     * @param string $code PHP code
     *
     * @return string
     */
    public function makeNocacheCode($code)
    {
        return "echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/<?php " .
               str_replace('^#^', '\'', addcslashes($code, '\'\\')) .
               "?>/*/%%SmartyNocache:{$this->nocache_hash}%%*/';\n";
    }

    /**
     * display compiler error messages without dying
     * If parameter $args is empty it is a parser detected syntax error.
     * In this case the parser is called to obtain information about expected tokens.
     * If parameter $args contains a string this is used as error message
     *
     * @param string    $args    individual error message or null
     * @param string    $line    line-number
     * @param null|bool $tagline if true the line number of last tag
     *
     * @throws \SmartyCompilerException when an unexpected token is found
     */
    public function trigger_template_error($args = null, $line = null, $tagline = null)
    {
        $lex = $this->parser->lex;
        if ($tagline === true) {
            // get line number of Tag
            $line = $lex->taglineno;
        } elseif (!isset($line)) {
            // get template source line which has error
            $line = $lex->line;
        } else {
            $line = (int)$line;
        }
        if (in_array(
            $this->template->source->type,
            array(
                'eval',
                'string'
            )
        )
        ) {
            $templateName = $this->template->source->type . ':' . trim(
                    preg_replace(
                        '![\t\r\n]+!',
                        ' ',
                        strlen($lex->data) > 40 ?
                            substr($lex->data, 0, 40) .
                            '...' : $lex->data
                    )
                );
        } else {
            $templateName = $this->template->source->type . ':' . $this->template->source->filepath;
        }
        //        $line += $this->trace_line_offset;
        $match = preg_split("/\n/", $lex->data);
        $error_text =
            'Syntax error in template "' . (empty($this->trace_filepath) ? $templateName : $this->trace_filepath) .
            '"  on line ' . ($line + $this->trace_line_offset) . ' "' .
            trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ])) . '" ';
        if (isset($args)) {
            // individual error message
            $error_text .= $args;
        } else {
            $expect = array();
            // expected token from parser
            $error_text .= ' - Unexpected "' . $lex->value . '"';
            if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) {
                foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {
                    $exp_token = $this->parser->yyTokenName[ $token ];
                    if (isset($lex->smarty_token_names[ $exp_token ])) {
                        // token type from lexer
                        $expect[] = '"' . $lex->smarty_token_names[ $exp_token ] . '"';
                    } else {
                        // otherwise internal token name
                        $expect[] = $this->parser->yyTokenName[ $token ];
                    }
                }
                $error_text .= ', expected one of: ' . implode(' , ', $expect);
            }
        }
        if ($this->smarty->_parserdebug) {
            $this->parser->errorRunDown();
            echo ob_get_clean();
            flush();
        }
        $e = new SmartyCompilerException($error_text);
        $e->line = $line;
        $e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ]));
        $e->desc = $args;
        $e->template = $this->template->source->filepath;
        throw $e;
    }

    /**
     * Return var_export() value with all white spaces removed
     *
     * @param mixed $value
     *
     * @return string
     */
    public function getVarExport($value)
    {
        return preg_replace('/\s/', '', var_export($value, true));
    }

    /**
     *  enter double quoted string
     *  - save tag stack count
     */
    public function enterDoubleQuote()
    {
        array_push($this->_tag_stack_count, $this->getTagStackCount());
    }

    /**
     * Return tag stack count
     *
     * @return int
     */
    public function getTagStackCount()
    {
        return count($this->_tag_stack);
    }

    /**
     * @param $lexerPreg
     *
     * @return mixed
     */
    public function replaceDelimiter($lexerPreg)
    {
        return str_replace(
            array('SMARTYldel', 'SMARTYliteral', 'SMARTYrdel', 'SMARTYautoliteral', 'SMARTYal'),
            array(
                $this->ldelPreg, $this->literalPreg, $this->rdelPreg,
                $this->smarty->getAutoLiteral() ? '{1,}' : '{9}',
                $this->smarty->getAutoLiteral() ? '' : '\\s*'
            ),
            $lexerPreg
        );
    }

    /**
     * Build lexer regular expressions for left and right delimiter and user defined literals
     */
    public function initDelimiterPreg()
    {
        $ldel = $this->smarty->getLeftDelimiter();
        $this->ldelLength = strlen($ldel);
        $this->ldelPreg = '';
        foreach (str_split($ldel, 1) as $chr) {
            $this->ldelPreg .= '[' . preg_quote($chr,'/') . ']';
        }
        $rdel = $this->smarty->getRightDelimiter();
        $this->rdelLength = strlen($rdel);
        $this->rdelPreg = '';
        foreach (str_split($rdel, 1) as $chr) {
            $this->rdelPreg .= '[' . preg_quote($chr,'/') . ']';
        }
        $literals = $this->smarty->getLiterals();
        if (!empty($literals)) {
            foreach ($literals as $key => $literal) {
                $literalPreg = '';
                foreach (str_split($literal, 1) as $chr) {
                    $literalPreg .= '[' . preg_quote($chr,'/') . ']';
                }
                $literals[ $key ] = $literalPreg;
            }
            $this->literalPreg = '|' . implode('|', $literals);
        } else {
            $this->literalPreg = '';
        }
    }

    /**
     *  leave double quoted string
     *  - throw exception if block in string was not closed
     *
     * @throws \SmartyCompilerException
     */
    public function leaveDoubleQuote()
    {
        if (array_pop($this->_tag_stack_count) !== $this->getTagStackCount()) {
            $tag = $this->getOpenBlockTag();
            $this->trigger_template_error(
                "unclosed '{{$tag}}' in doubled quoted string",
                null,
                true
            );
        }
    }

    /**
     * Get left delimiter preg
     *
     * @return string
     */
    public function getLdelPreg()
    {
        return $this->ldelPreg;
    }

    /**
     * Get right delimiter preg
     *
     * @return string
     */
    public function getRdelPreg()
    {
        return $this->rdelPreg;
    }

    /**
     * Get length of left delimiter
     *
     * @return int
     */
    public function getLdelLength()
    {
        return $this->ldelLength;
    }

    /**
     * Get length of right delimiter
     *
     * @return int
     */
    public function getRdelLength()
    {
        return $this->rdelLength;
    }

    /**
     * Get name of current open block tag
     *
     * @return string|boolean
     */
    public function getOpenBlockTag()
    {
        $tagCount = $this->getTagStackCount();
        if ($tagCount) {
            return $this->_tag_stack[ $tagCount - 1 ][ 0 ];
        } else {
            return false;
        }
    }

    /**
     * Check if $value contains variable elements
     *
     * @param mixed $value
     *
     * @return bool|int
     */
    public function isVariable($value)
    {
        if (is_string($value)) {
            return preg_match('/[$(]/', $value);
        }
        if (is_bool($value) || is_numeric($value)) {
            return false;
        }
        if (is_array($value)) {
            foreach ($value as $k => $v) {
                if ($this->isVariable($k) || $this->isVariable($v)) {
                    return true;
                }
            }
            return false;
        }
        return false;
    }

    /**
     * Get new prefix variable name
     *
     * @return string
     */
    public function getNewPrefixVariable()
    {
        ++self::$prefixVariableNumber;
        return $this->getPrefixVariable();
    }

    /**
     * Get current prefix variable name
     *
     * @return string
     */
    public function getPrefixVariable()
    {
        return '$_prefixVariable' . self::$prefixVariableNumber;
    }

    /**
     * append  code to prefix buffer
     *
     * @param string $code
     */
    public function appendPrefixCode($code)
    {
        $this->prefix_code[] = $code;
    }

    /**
     * get prefix code string
     *
     * @return string
     */
    public function getPrefixCode()
    {
        $code = '';
        $prefixArray = array_merge($this->prefix_code, array_pop($this->prefixCodeStack));
        $this->prefixCodeStack[] = array();
        foreach ($prefixArray as $c) {
            $code = $this->appendCode($code, $c);
        }
        $this->prefix_code = array();
        return $code;
    }

    /**
     * Save current required plugins
     *
     * @param bool $init if true init required plugins
     */
    public function saveRequiredPlugins($init = false)
    {
        $this->required_plugins_stack[] = $this->required_plugins;
        if ($init) {
            $this->required_plugins = array('compiled' => array(), 'nocache' => array());
        }
    }

    /**
     * Restore required plugins
     */
    public function restoreRequiredPlugins()
    {
        $this->required_plugins = array_pop($this->required_plugins_stack);
    }

    /**
     * Compile code to call Smarty_Internal_Template::_checkPlugins()
     * for required plugins
     *
     * @return string
     */
    public function compileRequiredPlugins()
    {
        $code = $this->compileCheckPlugins($this->required_plugins[ 'compiled' ]);
        if ($this->caching && !empty($this->required_plugins[ 'nocache' ])) {
            $code .= $this->makeNocacheCode($this->compileCheckPlugins($this->required_plugins[ 'nocache' ]));
        }
        return $code;
    }

    /**
     * Compile code to call Smarty_Internal_Template::_checkPlugins
     *   - checks if plugin is callable require otherwise
     *
     * @param $requiredPlugins
     *
     * @return string
     */
    public function compileCheckPlugins($requiredPlugins)
    {
        if (!empty($requiredPlugins)) {
            $plugins = array();
            foreach ($requiredPlugins as $plugin) {
                foreach ($plugin as $data) {
                    $plugins[] = $data;
                }
            }
            return '$_smarty_tpl->_checkPlugins(' . $this->getVarExport($plugins) . ');' . "\n";
        } else {
            return '';
        }
    }

    /**
     * method to compile a Smarty template
     *
     * @param mixed $_content template source
     * @param bool  $isTemplateSource
     *
     * @return bool true if compiling succeeded, false if it failed
     */
    abstract protected function doCompile($_content, $isTemplateSource = false);

    /**
     * Compile Tag
     *
     * @param string $tag       tag name
     * @param array  $args      array with tag attributes
     * @param array  $parameter array with compilation parameter
     *
     * @throws SmartyCompilerException
     * @throws SmartyException
     * @return string compiled code
     */
    private function compileTag2($tag, $args, $parameter)
    {
        $plugin_type = '';
        // $args contains the attributes parsed and compiled by the lexer/parser
        // assume that tag does compile into code, but creates no HTML output
        $this->has_code = true;
        // log tag/attributes
        if (isset($this->smarty->_cache[ 'get_used_tags' ])) {
            $this->template->_cache[ 'used_tags' ][] = array(
                $tag,
                $args
            );
        }
        // check nocache option flag
        foreach ($args as $arg) {
            if (!is_array($arg)) {
                if ($arg === "'nocache'" || $arg === 'nocache') {
                    $this->tag_nocache = true;
                }
            } else {
                foreach ($arg as $k => $v) {
                    if (($k === "'nocache'" || $k === 'nocache') && (trim($v, "'\" ") === 'true')) {
                        $this->tag_nocache = true;
                    }
                }
            }
        }
        // compile the smarty tag (required compile classes to compile the tag are auto loaded)
        if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) {
            if (isset($this->parent_compiler->tpl_function[ $tag ])
                || (isset($this->template->smarty->ext->_tplFunction)
                    && $this->template->smarty->ext->_tplFunction->getTplFunction($this->template, $tag) !== false)
            ) {
                // template defined by {template} tag
                $args[ '_attr' ][ 'name' ] = "'{$tag}'";
                $_output = $this->callTagCompiler('call', $args, $parameter);
            }
        }
        if ($_output !== false) {
            if ($_output !== true) {
                // did we get compiled code
                if ($this->has_code) {
                    // return compiled code
                    return $_output;
                }
            }
            // tag did not produce compiled code
            return null;
        } else {
            // map_named attributes
            if (isset($args[ '_attr' ])) {
                foreach ($args[ '_attr' ] as $key => $attribute) {
                    if (is_array($attribute)) {
                        $args = array_merge($args, $attribute);
                    }
                }
            }
            // not an internal compiler tag
            if (strlen($tag) < 6 || substr($tag, -5) !== 'close') {
                // check if tag is a registered object
                if (isset($this->smarty->registered_objects[ $tag ]) && isset($parameter[ 'object_method' ])) {
                    $method = $parameter[ 'object_method' ];
                    if (!in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ])
                        && (empty($this->smarty->registered_objects[ $tag ][ 1 ])
                            || in_array($method, $this->smarty->registered_objects[ $tag ][ 1 ]))
                    ) {
                        return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $method);
                    } elseif (in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ])) {
                        return $this->callTagCompiler(
                            'private_object_block_function',
                            $args,
                            $parameter,
                            $tag,
                            $method
                        );
                    } else {
                        // throw exception
                        $this->trigger_template_error(
                            'not allowed method "' . $method . '" in registered object "' .
                            $tag . '"',
                            null,
                            true
                        );
                    }
                }
                // check if tag is registered
                foreach (array(
                    Smarty::PLUGIN_COMPILER,
                    Smarty::PLUGIN_FUNCTION,
                    Smarty::PLUGIN_BLOCK,
                ) as $plugin_type) {
                    if (isset($this->smarty->registered_plugins[ $plugin_type ][ $tag ])) {
                        // if compiler function plugin call it now
                        if ($plugin_type === Smarty::PLUGIN_COMPILER) {
                            $new_args = array();
                            foreach ($args as $key => $mixed) {
                                if (is_array($mixed)) {
                                    $new_args = array_merge($new_args, $mixed);
                                } else {
                                    $new_args[ $key ] = $mixed;
                                }
                            }
                            if (!$this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 1 ]) {
                                $this->tag_nocache = true;
                            }
                            return call_user_func_array(
                                $this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 0 ],
                                array(
                                    $new_args,
                                    $this
                                )
                            );
                        }
                        // compile registered function or block function
                        if ($plugin_type === Smarty::PLUGIN_FUNCTION || $plugin_type === Smarty::PLUGIN_BLOCK) {
                            return $this->callTagCompiler(
                                'private_registered_' . $plugin_type,
                                $args,
                                $parameter,
                                $tag
                            );
                        }
                    }
                }
                // check plugins from plugins folder
                foreach ($this->plugin_search_order as $plugin_type) {
                    if ($plugin_type === Smarty::PLUGIN_COMPILER
                        && $this->smarty->loadPlugin('smarty_compiler_' . $tag)
                        && (!isset($this->smarty->security_policy)
                            || $this->smarty->security_policy->isTrustedTag($tag, $this))
                    ) {
                        $plugin = 'smarty_compiler_' . $tag;
                        if (is_callable($plugin)) {
                            // convert arguments format for old compiler plugins
                            $new_args = array();
                            foreach ($args as $key => $mixed) {
                                if (is_array($mixed)) {
                                    $new_args = array_merge($new_args, $mixed);
                                } else {
                                    $new_args[ $key ] = $mixed;
                                }
                            }
                            return $plugin($new_args, $this->smarty);
                        }
                        if (class_exists($plugin, false)) {
                            $plugin_object = new $plugin;
                            if (method_exists($plugin_object, 'compile')) {
                                return $plugin_object->compile($args, $this);
                            }
                        }
                        throw new SmartyException("Plugin '{$tag}' not callable");
                    } else {
                        if ($function = $this->getPlugin($tag, $plugin_type)) {
                            if (!isset($this->smarty->security_policy)
                                || $this->smarty->security_policy->isTrustedTag($tag, $this)
                            ) {
                                return $this->callTagCompiler(
                                    'private_' . $plugin_type . '_plugin',
                                    $args,
                                    $parameter,
                                    $tag,
                                    $function
                                );
                            }
                        }
                    }
                }
                if (is_callable($this->smarty->default_plugin_handler_func)) {
                    $found = false;
                    // look for already resolved tags
                    foreach ($this->plugin_search_order as $plugin_type) {
                        if (isset($this->default_handler_plugins[ $plugin_type ][ $tag ])) {
                            $found = true;
                            break;
                        }
                    }
                    if (!$found) {
                        // call default handler
                        foreach ($this->plugin_search_order as $plugin_type) {
                            if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) {
                                $found = true;
                                break;
                            }
                        }
                    }
                    if ($found) {
                        // if compiler function plugin call it now
                        if ($plugin_type === Smarty::PLUGIN_COMPILER) {
                            $new_args = array();
                            foreach ($args as $key => $mixed) {
                                if (is_array($mixed)) {
                                    $new_args = array_merge($new_args, $mixed);
                                } else {
                                    $new_args[ $key ] = $mixed;
                                }
                            }
                            return call_user_func_array(
                                $this->default_handler_plugins[ $plugin_type ][ $tag ][ 0 ],
                                array(
                                    $new_args,
                                    $this
                                )
                            );
                        } else {
                            return $this->callTagCompiler(
                                'private_registered_' . $plugin_type,
                                $args,
                                $parameter,
                                $tag
                            );
                        }
                    }
                }
            } else {
                // compile closing tag of block function
                $base_tag = substr($tag, 0, -5);
                // check if closing tag is a registered object
                if (isset($this->smarty->registered_objects[ $base_tag ]) && isset($parameter[ 'object_method' ])) {
                    $method = $parameter[ 'object_method' ];
                    if (in_array($method, $this->smarty->registered_objects[ $base_tag ][ 3 ])) {
                        return $this->callTagCompiler(
                            'private_object_block_function',
                            $args,
                            $parameter,
                            $tag,
                            $method
                        );
                    } else {
                        // throw exception
                        $this->trigger_template_error(
                            'not allowed closing tag method "' . $method .
                            '" in registered object "' . $base_tag . '"',
                            null,
                            true
                        );
                    }
                }
                // registered block tag ?
                if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ])
                    || isset($this->default_handler_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ])
                ) {
                    return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag);
                }
                // registered function tag ?
                if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_FUNCTION ][ $tag ])) {
                    return $this->callTagCompiler('private_registered_function', $args, $parameter, $tag);
                }
                // block plugin?
                if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) {
                    return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function);
                }
                // function plugin?
                if ($function = $this->getPlugin($tag, Smarty::PLUGIN_FUNCTION)) {
                    if (!isset($this->smarty->security_policy)
                        || $this->smarty->security_policy->isTrustedTag($tag, $this)
                    ) {
                        return $this->callTagCompiler('private_function_plugin', $args, $parameter, $tag, $function);
                    }
                }
                // registered compiler plugin ?
                if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ])) {
                    // if compiler function plugin call it now
                    $args = array();
                    if (!$this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 1 ]) {
                        $this->tag_nocache = true;
                    }
                    return call_user_func_array(
                        $this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 0 ],
                        array(
                            $args,
                            $this
                        )
                    );
                }
                if ($this->smarty->loadPlugin('smarty_compiler_' . $tag)) {
                    $plugin = 'smarty_compiler_' . $tag;
                    if (is_callable($plugin)) {
                        return $plugin($args, $this->smarty);
                    }
                    if (class_exists($plugin, false)) {
                        $plugin_object = new $plugin;
                        if (method_exists($plugin_object, 'compile')) {
                            return $plugin_object->compile($args, $this);
                        }
                    }
                    throw new SmartyException("Plugin '{$tag}' not callable");
                }
            }
            $this->trigger_template_error("unknown tag '{$tag}'", null, true);
        }
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <?php
/*
 * This file is part of Smarty.
 *
 * (c) 2015 Uwe Tews
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * Smarty_Internal_Templatelexer
 * This is the template file lexer.
 * It is generated from the smarty_internal_templatelexer.plex file
 *
 *
 * @author Uwe Tews <uwe.tews@googlemail.com>
 */
class Smarty_Internal_Templatelexer
{
    const TEXT               = 1;
    const TAG                = 2;
    const TAGBODY            = 3;
    const LITERAL            = 4;
    const DOUBLEQUOTEDSTRING = 5;

    /**
     * Source
     *
     * @var string
     */
    public $data;

    /**
     * Source length
     *
     * @var int
     */
    public $dataLength = null;

    /**
     * byte counter
     *
     * @var int
     */
    public $counter;

    /**
     * token number
     *
     * @var int
     */
    public $token;

    /**
     * token value
     *
     * @var string
     */
    public $value;

    /**
     * current line
     *
     * @var int
     */
    public $line;

    /**
     * tag start line
     *
     * @var
     */
    public $taglineno;

    /**
     * php code type
     *
     * @var string
     */
    public $phpType = '';

    /**
     * state number
     *
     * @var int
     */
    public $state = 1;

    /**
     * Smarty object
     *
     * @var Smarty
     */
    public $smarty = null;

    /**
     * compiler object
     *
     * @var Smarty_Internal_TemplateCompilerBase
     */
    public $compiler = null;

    /**
     * trace file
     *
     * @var resource
     */
    public $yyTraceFILE;

    /**
     * trace prompt
     *
     * @var string
     */
    public $yyTracePrompt;

    /**
     * XML flag true while processing xml
     *
     * @var bool
     */
    public $is_xml = false;

    /**
     * state names
     *
     * @var array
     */
    public $state_name = array(1 => 'TEXT', 2 => 'TAG', 3 => 'TAGBODY', 4 => 'LITERAL', 5 => 'DOUBLEQUOTEDSTRING',);

    /**
     * token names
     *
     * @var array
     */
    public $smarty_token_names = array(        // Text for parser error messages
                                               'NOT'         => '(!,not)',
                                               'OPENP'       => '(',
                                               'CLOSEP'      => ')',
                                               'OPENB'       => '[',
                                               'CLOSEB'      => ']',
                                               'PTR'         => '->',
                                               'APTR'        => '=>',
                                               'EQUAL'       => '=',
                                               'NUMBER'      => 'number',
                                               'UNIMATH'     => '+" , "-',
                                               'MATH'        => '*" , "/" , "%',
                                               'INCDEC'      => '++" , "--',
                                               'SPACE'       => ' ',
                                               'DOLLAR'      => '$',
                                               'SEMICOLON'   => ';',
                                               'COLON'       => ':',
                                               'DOUBLECOLON' => '::',
                                               'AT'          => '@',
                                               'HATCH'       => '#',
                                               'QUOTE'       => '"',
                                               'BACKTICK'    => '`',
                                               'VERT'        => '"|" modifier',
                                               'DOT'         => '.',
                                               'COMMA'       => '","',
                                               'QMARK'       => '"?"',
                                               'ID'          => 'id, name',
                                               'TEXT'        => 'text',
                                               'LDELSLASH'   => '{/..} closing tag',
                                               'LDEL'        => '{...} Smarty tag',
                                               'COMMENT'     => 'comment',
                                               'AS'          => 'as',
                                               'TO'          => 'to',
                                               'PHP'         => '"<?php", "<%", "{php}" tag',
                                               'LOGOP'       => '"<", "==" ... logical operator',
                                               'TLOGOP'      => '"lt", "eq" ... logical operator; "is div by" ... if condition',
                                               'SCOND'       => '"is even" ... if condition',
    );

    /**
     * literal tag nesting level
     *
     * @var int
     */
    private $literal_cnt = 0;

    /**
     * preg token pattern for state TEXT
     *
     * @var string
     */
    private $yy_global_pattern1 = null;

    /**
     * preg token pattern for state TAG
     *
     * @var string
     */
    private $yy_global_pattern2 = null;

    /**
     * preg token pattern for state TAGBODY
     *
     * @var string
     */
    private $yy_global_pattern3 = null;

    /**
     * preg token pattern for state LITERAL
     *
     * @var string
     */
    private $yy_global_pattern4 = null;

    /**
     * preg token pattern for state DOUBLEQUOTEDSTRING
     *
     * @var null
     */
    private $yy_global_pattern5 = null;

    /**
     * preg token pattern for text
     *
     * @var null
     */
    private $yy_global_text = null;

    /**
     * preg token pattern for literal
     *
     * @var null
     */
    private $yy_global_literal = null;

    private $_yy_state         = 1;

    private $_yy_stack         = array();

    /**
     * constructor
     *
     * @param   string                             $source template source
     * @param Smarty_Internal_TemplateCompilerBase $compiler
     */
    public function __construct($source, Smarty_Internal_TemplateCompilerBase $compiler)
    {
        $this->data = $source;
        $this->dataLength = strlen($this->data);
        $this->counter = 0;
        if (preg_match('/^\xEF\xBB\xBF/i', $this->data, $match)) {
            $this->counter += strlen($match[ 0 ]);
        }
        $this->line = 1;
        $this->smarty = $compiler->template->smarty;
        $this->compiler = $compiler;
        $this->compiler->initDelimiterPreg();
        $this->smarty_token_names[ 'LDEL' ] = $this->smarty->getLeftDelimiter();
        $this->smarty_token_names[ 'RDEL' ] = $this->smarty->getRightDelimiter();
    }

    /**
     * open lexer/parser trace file
     *
     */
    public function PrintTrace()
    {
        $this->yyTraceFILE = fopen('php://output', 'w');
        $this->yyTracePrompt = '<br>';
    }

    /**
     * replace placeholders with runtime preg  code
     *
     * @param string $preg
     *
     * @return string
     */
    public function replace($preg)
    {
        return $this->compiler->replaceDelimiter($preg);
    }

    /**
     * check if current value is an autoliteral left delimiter
     *
     * @return bool
     */
    public function isAutoLiteral()
    {
        return $this->smarty->getAutoLiteral() && isset($this->value[ $this->compiler->getLdelLength() ]) ?
            strpos(" \n\t\r", $this->value[ $this->compiler->getLdelLength() ]) !== false : false;
    } // end function

    public function yylex()
    {
        return $this->{'yylex' . $this->_yy_state}();
    }

    public function yypushstate($state)
    {
        if ($this->yyTraceFILE) {
            fprintf($this->yyTraceFILE, "%sState push %s\n", $this->yyTracePrompt,
                isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state);
        }
        array_push($this->_yy_stack, $this->_yy_state);
        $this->_yy_state = $state;
        if ($this->yyTraceFILE) {
            fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt,
                isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state);
        }
    }

    public function yypopstate()
    {
        if ($this->yyTraceFILE) {
            fprintf($this->yyTraceFILE, "%sState pop %s\n", $this->yyTracePrompt,
                isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state);
        }
        $this->_yy_state = array_pop($this->_yy_stack);
        if ($this->yyTraceFILE) {
            fprintf($this->yyTraceFILE, "%snew State %s\n", $this->yyTracePrompt,
                isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state);
        }
    }

    public function yybegin($state)
    {
        $this->_yy_state = $state;
        if ($this->yyTraceFILE) {
            fprintf($this->yyTraceFILE, "%sState set %s\n", $this->yyTracePrompt,
                isset($this->state_name[ $this->_yy_state ]) ? $this->state_name[ $this->_yy_state ] : $this->_yy_state);
        }
    }

    public function yylex1()
    {
        if (!isset($this->yy_global_pattern1)) {
            $this->yy_global_pattern1 =
                $this->replace("/\G([{][}])|\G((SMARTYldel)SMARTYal[*])|\G((SMARTYldel)SMARTYalphp([ ].*?)?SMARTYrdel|(SMARTYldel)SMARTYal[\/]phpSMARTYrdel)|\G((SMARTYldel)SMARTYautoliteral\\s+SMARTYliteral)|\G((SMARTYldel)SMARTYalliteral\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/]literal\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal)|\G([<][?]((php\\s+|=)|\\s+)|[<][%]|[<][?]xml\\s+|[<]script\\s+language\\s*=\\s*[\"']?\\s*php\\s*[\"']?\\s*[>]|[?][>]|[%][>])|\G([\S\s])/isS");
        }
        if (!isset($this->dataLength)) {
            $this->dataLength = strlen($this->data);
        }
        if ($this->counter >= $this->dataLength) {
            return false; // end of input
        }
        do {
            if (preg_match($this->yy_global_pattern1, $this->data, $yymatches, 0, $this->counter)) {
                if (!isset($yymatches[ 0 ][ 1 ])) {
                    $yymatches = preg_grep("/(.|\s)+/", $yymatches);
                } else {
                    $yymatches = array_filter($yymatches);
                }
                if (empty($yymatches)) {
                    throw new Exception('Error: lexing failed because a rule matched' .
                                        ' an empty string.  Input "' . substr($this->data,
                            $this->counter, 5) . '... state TEXT');
                }
                next($yymatches); // skip global match
                $this->token = key($yymatches); // token number
                $this->value = current($yymatches); // token value
                $r = $this->{'yy_r1_' . $this->token}();
                if ($r === null) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    // accept this token
                    return true;
                } elseif ($r === true) {
                    // we have changed state
                    // process this token in the new state
                    return $this->yylex();
                } elseif ($r === false) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    if ($this->counter >= $this->dataLength) {
                        return false; // end of input
                    }
                    // skip this token
                    continue;
                }
            } else {
                throw new Exception('Unexpected input at line ' . $this->line .
                                    ': ' . $this->data[ $this->counter ]);
            }
            break;
        } while (true);
    }

    public function yy_r1_1()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }

    public function yy_r1_2()
    {
        $to = $this->dataLength;
        preg_match("/[*]{$this->compiler->getRdelPreg()}[\n]?/", $this->data, $match, PREG_OFFSET_CAPTURE,
            $this->counter);
        if (isset($match[ 0 ][ 1 ])) {
            $to = $match[ 0 ][ 1 ] + strlen($match[ 0 ][ 0 ]);
        } else {
            $this->compiler->trigger_template_error("missing or misspelled comment closing tag '{$this->smarty->getRightDelimiter()}'");
        }
        $this->value = substr($this->data, $this->counter, $to - $this->counter);
        return false;
    }

    public function yy_r1_4()
    {
        $this->compiler->getTagCompiler('private_php')->parsePhp($this);
    }

    public function yy_r1_8()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }

    public function yy_r1_10()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LITERALSTART;
        $this->yypushstate(self::LITERAL);
    }

    public function yy_r1_12()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
        $this->yypushstate(self::LITERAL);
    } // end function

    public function yy_r1_14()
    {
        $this->yypushstate(self::TAG);
        return true;
    }

    public function yy_r1_16()
    {
        $this->compiler->getTagCompiler('private_php')->parsePhp($this);
    }

    public function yy_r1_19()
    {
        if (!isset($this->yy_global_text)) {
            $this->yy_global_text =
                $this->replace('/(SMARTYldel)SMARTYal|[<][?]((php\s+|=)|\s+)|[<][%]|[<][?]xml\s+|[<]script\s+language\s*=\s*["\']?\s*php\s*["\']?\s*[>]|[?][>]|[%][>]SMARTYliteral/isS');
        }
        $to = $this->dataLength;
        preg_match($this->yy_global_text, $this->data, $match, PREG_OFFSET_CAPTURE, $this->counter);
        if (isset($match[ 0 ][ 1 ])) {
            $to = $match[ 0 ][ 1 ];
        }
        $this->value = substr($this->data, $this->counter, $to - $this->counter);
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }

    public function yylex2()
    {
        if (!isset($this->yy_global_pattern2)) {
            $this->yy_global_pattern2 =
                $this->replace("/\G((SMARTYldel)SMARTYal(if|elseif|else if|while)\\s+)|\G((SMARTYldel)SMARTYalfor\\s+)|\G((SMARTYldel)SMARTYalforeach(?![^\s]))|\G((SMARTYldel)SMARTYalsetfilter\\s+)|\G((SMARTYldel)SMARTYalmake_nocache\\s+)|\G((SMARTYldel)SMARTYal[0-9]*[a-zA-Z_]\\w*(\\s+nocache)?\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[$]smarty\\.block\\.(child|parent)\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/][0-9]*[a-zA-Z_]\\w*\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[$][0-9]*[a-zA-Z_]\\w*(\\s+nocache)?\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/])|\G((SMARTYldel)SMARTYal)/isS");
        }
        if (!isset($this->dataLength)) {
            $this->dataLength = strlen($this->data);
        }
        if ($this->counter >= $this->dataLength) {
            return false; // end of input
        }
        do {
            if (preg_match($this->yy_global_pattern2, $this->data, $yymatches, 0, $this->counter)) {
                if (!isset($yymatches[ 0 ][ 1 ])) {
                    $yymatches = preg_grep("/(.|\s)+/", $yymatches);
                } else {
                    $yymatches = array_filter($yymatches);
                }
                if (empty($yymatches)) {
                    throw new Exception('Error: lexing failed because a rule matched' .
                                        ' an empty string.  Input "' . substr($this->data,
                            $this->counter, 5) . '... state TAG');
                }
                next($yymatches); // skip global match
                $this->token = key($yymatches); // token number
                $this->value = current($yymatches); // token value
                $r = $this->{'yy_r2_' . $this->token}();
                if ($r === null) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    // accept this token
                    return true;
                } elseif ($r === true) {
                    // we have changed state
                    // process this token in the new state
                    return $this->yylex();
                } elseif ($r === false) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    if ($this->counter >= $this->dataLength) {
                        return false; // end of input
                    }
                    // skip this token
                    continue;
                }
            } else {
                throw new Exception('Unexpected input at line ' . $this->line .
                                    ': ' . $this->data[ $this->counter ]);
            }
            break;
        } while (true);
    }

    public function yy_r2_1()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LDELIF;
        $this->yybegin(self::TAGBODY);
        $this->taglineno = $this->line;
    }

    public function yy_r2_4()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LDELFOR;
        $this->yybegin(self::TAGBODY);
        $this->taglineno = $this->line;
    }

    public function yy_r2_6()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LDELFOREACH;
        $this->yybegin(self::TAGBODY);
        $this->taglineno = $this->line;
    }

    public function yy_r2_8()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LDELSETFILTER;
        $this->yybegin(self::TAGBODY);
        $this->taglineno = $this->line;
    }

    public function yy_r2_10()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LDELMAKENOCACHE;
        $this->yybegin(self::TAGBODY);
        $this->taglineno = $this->line;
    }

    public function yy_r2_12()
    {
        $this->yypopstate();
        $this->token = Smarty_Internal_Templateparser::TP_SIMPLETAG;
        $this->taglineno = $this->line;
    }

    public function yy_r2_15()
    {
        $this->yypopstate();
        $this->token = Smarty_Internal_Templateparser::TP_SMARTYBLOCKCHILDPARENT;
        $this->taglineno = $this->line;
    }

    public function yy_r2_18()
    {
        $this->yypopstate();
        $this->token = Smarty_Internal_Templateparser::TP_CLOSETAG;
        $this->taglineno = $this->line;
    }

    public function yy_r2_20()
    {
        if ($this->_yy_stack[ count($this->_yy_stack) - 1 ] === self::TEXT) {
            $this->yypopstate();
            $this->token = Smarty_Internal_Templateparser::TP_SIMPELOUTPUT;
            $this->taglineno = $this->line;
        } else {
            $this->value = $this->smarty->getLeftDelimiter();
            $this->token = Smarty_Internal_Templateparser::TP_LDEL;
            $this->yybegin(self::TAGBODY);
            $this->taglineno = $this->line;
        }
    } // end function

    public function yy_r2_23()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LDELSLASH;
        $this->yybegin(self::TAGBODY);
        $this->taglineno = $this->line;
    }

    public function yy_r2_25()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LDEL;
        $this->yybegin(self::TAGBODY);
        $this->taglineno = $this->line;
    }

    public function yylex3()
    {
        if (!isset($this->yy_global_pattern3)) {
            $this->yy_global_pattern3 =
                $this->replace("/\G(\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal)|\G([\"])|\G('[^'\\\\]*(?:\\\\.[^'\\\\]*)*')|\G([$][0-9]*[a-zA-Z_]\\w*)|\G([$])|\G(\\s+is\\s+in\\s+)|\G(\\s+as\\s+)|\G(\\s+to\\s+)|\G(\\s+step\\s+)|\G(\\s+instanceof\\s+)|\G(\\s*([!=][=]{1,2}|[<][=>]?|[>][=]?|[&|]{2})\\s*)|\G(\\s+(eq|ne|neq|gt|ge|gte|lt|le|lte|mod|and|or|xor)\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even|div)\\s+by\\s+)|\G(\\s+is\\s+(not\\s+)?(odd|even))|\G([!]\\s*|not\\s+)|\G([(](int(eger)?|bool(ean)?|float|double|real|string|binary|array|object)[)]\\s*)|\G(\\s*[(]\\s*)|\G(\\s*[)])|\G(\\[\\s*)|\G(\\s*\\])|\G(\\s*[-][>]\\s*)|\G(\\s*[=][>]\\s*)|\G(\\s*[=]\\s*)|\G(([+]|[-]){2})|\G(\\s*([+]|[-])\\s*)|\G(\\s*([*]{1,2}|[%\/^&]|[<>]{2})\\s*)|\G([@])|\G(array\\s*[(]\\s*)|\G([#])|\G(\\s+[0-9]*[a-zA-Z_][a-zA-Z0-9_\-:]*\\s*[=]\\s*)|\G(([0-9]*[a-zA-Z_]\\w*)?(\\\\[0-9]*[a-zA-Z_]\\w*)+)|\G([0-9]*[a-zA-Z_]\\w*)|\G(\\d+)|\G([`])|\G([|][@]?)|\G([.])|\G(\\s*[,]\\s*)|\G(\\s*[;]\\s*)|\G([:]{2})|\G(\\s*[:]\\s*)|\G(\\s*[?]\\s*)|\G(0[xX][0-9a-fA-F]+)|\G(\\s+)|\G([\S\s])/isS");
        }
        if (!isset($this->dataLength)) {
            $this->dataLength = strlen($this->data);
        }
        if ($this->counter >= $this->dataLength) {
            return false; // end of input
        }
        do {
            if (preg_match($this->yy_global_pattern3, $this->data, $yymatches, 0, $this->counter)) {
                if (!isset($yymatches[ 0 ][ 1 ])) {
                    $yymatches = preg_grep("/(.|\s)+/", $yymatches);
                } else {
                    $yymatches = array_filter($yymatches);
                }
                if (empty($yymatches)) {
                    throw new Exception('Error: lexing failed because a rule matched' .
                                        ' an empty string.  Input "' . substr($this->data,
                            $this->counter, 5) . '... state TAGBODY');
                }
                next($yymatches); // skip global match
                $this->token = key($yymatches); // token number
                $this->value = current($yymatches); // token value
                $r = $this->{'yy_r3_' . $this->token}();
                if ($r === null) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    // accept this token
                    return true;
                } elseif ($r === true) {
                    // we have changed state
                    // process this token in the new state
                    return $this->yylex();
                } elseif ($r === false) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    if ($this->counter >= $this->dataLength) {
                        return false; // end of input
                    }
                    // skip this token
                    continue;
                }
            } else {
                throw new Exception('Unexpected input at line ' . $this->line .
                                    ': ' . $this->data[ $this->counter ]);
            }
            break;
        } while (true);
    }

    public function yy_r3_1()
    {
        $this->token = Smarty_Internal_Templateparser::TP_RDEL;
        $this->yypopstate();
    }

    public function yy_r3_2()
    {
        $this->yypushstate(self::TAG);
        return true;
    }

    public function yy_r3_4()
    {
        $this->token = Smarty_Internal_Templateparser::TP_QUOTE;
        $this->yypushstate(self::DOUBLEQUOTEDSTRING);
        $this->compiler->enterDoubleQuote();
    }

    public function yy_r3_5()
    {
        $this->token = Smarty_Internal_Templateparser::TP_SINGLEQUOTESTRING;
    }

    public function yy_r3_6()
    {
        $this->token = Smarty_Internal_Templateparser::TP_DOLLARID;
    }

    public function yy_r3_7()
    {
        $this->token = Smarty_Internal_Templateparser::TP_DOLLAR;
    }

    public function yy_r3_8()
    {
        $this->token = Smarty_Internal_Templateparser::TP_ISIN;
    }

    public function yy_r3_9()
    {
        $this->token = Smarty_Internal_Templateparser::TP_AS;
    }

    public function yy_r3_10()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TO;
    }

    public function yy_r3_11()
    {
        $this->token = Smarty_Internal_Templateparser::TP_STEP;
    }

    public function yy_r3_12()
    {
        $this->token = Smarty_Internal_Templateparser::TP_INSTANCEOF;
    }

    public function yy_r3_13()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LOGOP;
    }

    public function yy_r3_15()
    {
        $this->token = Smarty_Internal_Templateparser::TP_SLOGOP;
    }

    public function yy_r3_17()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TLOGOP;
    }

    public function yy_r3_20()
    {
        $this->token = Smarty_Internal_Templateparser::TP_SINGLECOND;
    }

    public function yy_r3_23()
    {
        $this->token = Smarty_Internal_Templateparser::TP_NOT;
    }

    public function yy_r3_24()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TYPECAST;
    }

    public function yy_r3_28()
    {
        $this->token = Smarty_Internal_Templateparser::TP_OPENP;
    }

    public function yy_r3_29()
    {
        $this->token = Smarty_Internal_Templateparser::TP_CLOSEP;
    }

    public function yy_r3_30()
    {
        $this->token = Smarty_Internal_Templateparser::TP_OPENB;
    }

    public function yy_r3_31()
    {
        $this->token = Smarty_Internal_Templateparser::TP_CLOSEB;
    }

    public function yy_r3_32()
    {
        $this->token = Smarty_Internal_Templateparser::TP_PTR;
    }

    public function yy_r3_33()
    {
        $this->token = Smarty_Internal_Templateparser::TP_APTR;
    }

    public function yy_r3_34()
    {
        $this->token = Smarty_Internal_Templateparser::TP_EQUAL;
    }

    public function yy_r3_35()
    {
        $this->token = Smarty_Internal_Templateparser::TP_INCDEC;
    }

    public function yy_r3_37()
    {
        $this->token = Smarty_Internal_Templateparser::TP_UNIMATH;
    }

    public function yy_r3_39()
    {
        $this->token = Smarty_Internal_Templateparser::TP_MATH;
    }

    public function yy_r3_41()
    {
        $this->token = Smarty_Internal_Templateparser::TP_AT;
    }

    public function yy_r3_42()
    {
        $this->token = Smarty_Internal_Templateparser::TP_ARRAYOPEN;
    }

    public function yy_r3_43()
    {
        $this->token = Smarty_Internal_Templateparser::TP_HATCH;
    }

    public function yy_r3_44()
    {
        // resolve conflicts with shorttag and right_delimiter starting with '='
        if (substr($this->data, $this->counter + strlen($this->value) - 1, $this->compiler->getRdelLength()) ===
            $this->smarty->getRightDelimiter()) {
            preg_match('/\s+/', $this->value, $match);
            $this->value = $match[ 0 ];
            $this->token = Smarty_Internal_Templateparser::TP_SPACE;
        } else {
            $this->token = Smarty_Internal_Templateparser::TP_ATTR;
        }
    }

    public function yy_r3_45()
    {
        $this->token = Smarty_Internal_Templateparser::TP_NAMESPACE;
    }

    public function yy_r3_48()
    {
        $this->token = Smarty_Internal_Templateparser::TP_ID;
    }

    public function yy_r3_49()
    {
        $this->token = Smarty_Internal_Templateparser::TP_INTEGER;
    }

    public function yy_r3_50()
    {
        $this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
        $this->yypopstate();
    }

    public function yy_r3_51()
    {
        $this->token = Smarty_Internal_Templateparser::TP_VERT;
    }

    public function yy_r3_52()
    {
        $this->token = Smarty_Internal_Templateparser::TP_DOT;
    }

    public function yy_r3_53()
    {
        $this->token = Smarty_Internal_Templateparser::TP_COMMA;
    }

    public function yy_r3_54()
    {
        $this->token = Smarty_Internal_Templateparser::TP_SEMICOLON;
    }

    public function yy_r3_55()
    {
        $this->token = Smarty_Internal_Templateparser::TP_DOUBLECOLON;
    }

    public function yy_r3_56()
    {
        $this->token = Smarty_Internal_Templateparser::TP_COLON;
    }

    public function yy_r3_57()
    {
        $this->token = Smarty_Internal_Templateparser::TP_QMARK;
    }

    public function yy_r3_58()
    {
        $this->token = Smarty_Internal_Templateparser::TP_HEX;
    }

    public function yy_r3_59()
    {
        $this->token = Smarty_Internal_Templateparser::TP_SPACE;
    } // end function

    public function yy_r3_60()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }

    public function yylex4()
    {
        if (!isset($this->yy_global_pattern4)) {
            $this->yy_global_pattern4 =
                $this->replace("/\G((SMARTYldel)SMARTYalliteral\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/]literal\\s*SMARTYrdel)|\G([\S\s])/isS");
        }
        if (!isset($this->dataLength)) {
            $this->dataLength = strlen($this->data);
        }
        if ($this->counter >= $this->dataLength) {
            return false; // end of input
        }
        do {
            if (preg_match($this->yy_global_pattern4, $this->data, $yymatches, 0, $this->counter)) {
                if (!isset($yymatches[ 0 ][ 1 ])) {
                    $yymatches = preg_grep("/(.|\s)+/", $yymatches);
                } else {
                    $yymatches = array_filter($yymatches);
                }
                if (empty($yymatches)) {
                    throw new Exception('Error: lexing failed because a rule matched' .
                                        ' an empty string.  Input "' . substr($this->data,
                            $this->counter, 5) . '... state LITERAL');
                }
                next($yymatches); // skip global match
                $this->token = key($yymatches); // token number
                $this->value = current($yymatches); // token value
                $r = $this->{'yy_r4_' . $this->token}();
                if ($r === null) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    // accept this token
                    return true;
                } elseif ($r === true) {
                    // we have changed state
                    // process this token in the new state
                    return $this->yylex();
                } elseif ($r === false) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    if ($this->counter >= $this->dataLength) {
                        return false; // end of input
                    }
                    // skip this token
                    continue;
                }
            } else {
                throw new Exception('Unexpected input at line ' . $this->line .
                                    ': ' . $this->data[ $this->counter ]);
            }
            break;
        } while (true);
    }

    public function yy_r4_1()
    {
        $this->literal_cnt++;
        $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
    }

    public function yy_r4_3()
    {
        if ($this->literal_cnt) {
            $this->literal_cnt--;
            $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
        } else {
            $this->token = Smarty_Internal_Templateparser::TP_LITERALEND;
            $this->yypopstate();
        }
    }

    public function yy_r4_5()
    {
        if (!isset($this->yy_global_literal)) {
            $this->yy_global_literal = $this->replace('/(SMARTYldel)SMARTYal[\/]?literalSMARTYrdel/isS');
        }
        $to = $this->dataLength;
        preg_match($this->yy_global_literal, $this->data, $match, PREG_OFFSET_CAPTURE, $this->counter);
        if (isset($match[ 0 ][ 1 ])) {
            $to = $match[ 0 ][ 1 ];
        } else {
            $this->compiler->trigger_template_error("missing or misspelled literal closing tag");
        }
        $this->value = substr($this->data, $this->counter, $to - $this->counter);
        $this->token = Smarty_Internal_Templateparser::TP_LITERAL;
    } // end function

    public function yylex5()
    {
        if (!isset($this->yy_global_pattern5)) {
            $this->yy_global_pattern5 =
                $this->replace("/\G((SMARTYldel)SMARTYautoliteral\\s+SMARTYliteral)|\G((SMARTYldel)SMARTYalliteral\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/]literal\\s*SMARTYrdel)|\G((SMARTYldel)SMARTYal[\/])|\G((SMARTYldel)SMARTYal[0-9]*[a-zA-Z_]\\w*)|\G((SMARTYldel)SMARTYal)|\G([\"])|\G([`][$])|\G([$][0-9]*[a-zA-Z_]\\w*)|\G([$])|\G(([^\"\\\\]*?)((?:\\\\.[^\"\\\\]*?)*?)(?=((SMARTYldel)SMARTYal|\\$|`\\$|\"SMARTYliteral)))|\G([\S\s])/isS");
        }
        if (!isset($this->dataLength)) {
            $this->dataLength = strlen($this->data);
        }
        if ($this->counter >= $this->dataLength) {
            return false; // end of input
        }
        do {
            if (preg_match($this->yy_global_pattern5, $this->data, $yymatches, 0, $this->counter)) {
                if (!isset($yymatches[ 0 ][ 1 ])) {
                    $yymatches = preg_grep("/(.|\s)+/", $yymatches);
                } else {
                    $yymatches = array_filter($yymatches);
                }
                if (empty($yymatches)) {
                    throw new Exception('Error: lexing failed because a rule matched' .
                                        ' an empty string.  Input "' . substr($this->data,
                            $this->counter, 5) . '... state DOUBLEQUOTEDSTRING');
                }
                next($yymatches); // skip global match
                $this->token = key($yymatches); // token number
                $this->value = current($yymatches); // token value
                $r = $this->{'yy_r5_' . $this->token}();
                if ($r === null) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    // accept this token
                    return true;
                } elseif ($r === true) {
                    // we have changed state
                    // process this token in the new state
                    return $this->yylex();
                } elseif ($r === false) {
                    $this->counter += strlen($this->value);
                    $this->line += substr_count($this->value, "\n");
                    if ($this->counter >= $this->dataLength) {
                        return false; // end of input
                    }
                    // skip this token
                    continue;
                }
            } else {
                throw new Exception('Unexpected input at line ' . $this->line .
                                    ': ' . $this->data[ $this->counter ]);
            }
            break;
        } while (true);
    }

    public function yy_r5_1()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }

    public function yy_r5_3()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }

    public function yy_r5_5()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }

    public function yy_r5_7()
    {
        $this->yypushstate(self::TAG);
        return true;
    }

    public function yy_r5_9()
    {
        $this->yypushstate(self::TAG);
        return true;
    }

    public function yy_r5_11()
    {
        $this->token = Smarty_Internal_Templateparser::TP_LDEL;
        $this->taglineno = $this->line;
        $this->yypushstate(self::TAGBODY);
    }

    public function yy_r5_13()
    {
        $this->token = Smarty_Internal_Templateparser::TP_QUOTE;
        $this->yypopstate();
    }

    public function yy_r5_14()
    {
        $this->token = Smarty_Internal_Templateparser::TP_BACKTICK;
        $this->value = substr($this->value, 0, -1);
        $this->yypushstate(self::TAGBODY);
        $this->taglineno = $this->line;
    }

    public function yy_r5_15()
    {
        $this->token = Smarty_Internal_Templateparser::TP_DOLLARID;
    }

    public function yy_r5_16()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }

    public function yy_r5_17()
    {
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }

    public function yy_r5_22()
    {
        $to = $this->dataLength;
        $this->value = substr($this->data, $this->counter, $to - $this->counter);
        $this->token = Smarty_Internal_Templateparser::TP_TEXT;
    }
}

     
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       <?php
/**
 * Smarty Internal TestInstall
 * Test Smarty installation
 *
 * @package    Smarty
 * @subpackage Utilities
 * @author     Uwe Tews
 */

/**
 * TestInstall class
 *
 * @package    Smarty
 * @subpackage Utilities
 */
class Smarty_Internal_TestInstall
{
    /**
     * diagnose Smarty setup
     * If $errors is secified, the diagnostic report will be appended to the array, rather than being output.
     *
     * @param \Smarty $smarty
     * @param array   $errors array to push results into rather than outputting them
     *
     * @return bool status, true if everything is fine, false else
     */
    public static function testInstall(Smarty $smarty, &$errors = null)
    {
        $status = true;
        if ($errors === null) {
            echo "<PRE>\n";
            echo "Smarty Installation test...\n";
            echo "Testing template directory...\n";
        }
        $_stream_resolve_include_path = function_exists('stream_resolve_include_path');
        // test if all registered template_dir are accessible
        foreach ($smarty->getTemplateDir() as $template_dir) {
            $_template_dir = $template_dir;
            $template_dir = realpath($template_dir);
            // resolve include_path or fail existence
            if (!$template_dir) {
                if ($smarty->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_template_dir)) {
                    // try PHP include_path
                    if ($_stream_resolve_include_path) {
                        $template_dir = stream_resolve_include_path($_template_dir);
                    } else {
                        $template_dir = $smarty->ext->_getIncludePath->getIncludePath($_template_dir, null, $smarty);
                    }
                    if ($template_dir !== false) {
                        if ($errors === null) {
                            echo "$template_dir is OK.\n";
                        }
                        continue;
                    } else {
                        $status = false;
                        $message =
                            "FAILED: $_template_dir does not exist (and couldn't be found in include_path either)";
                        if ($errors === null) {
                            echo $message . ".\n";
                        } else {
                            $errors[ 'template_dir' ] = $message;
                        }
                        continue;
                    }
                } else {
                    $status = false;
                    $message = "FAILED: $_template_dir does not exist";
                    if ($errors === null) {
                        echo $message . ".\n";
                    } else {
                        $errors[ 'template_dir' ] = $message;
                    }
                    continue;
                }
            }
            if (!is_dir($template_dir)) {
                $status = false;
                $message = "FAILED: $template_dir is not a directory";
                if ($errors === null) {
                    echo $message . ".\n";
                } else {
                    $errors[ 'template_dir' ] = $message;
                }
            } elseif (!is_readable($template_dir)) {
                $status = false;
                $message = "FAILED: $template_dir is not readable";
                if ($errors === null) {
                    echo $message . ".\n";
                } else {
                    $errors[ 'template_dir' ] = $message;
                }
            } else {
                if ($errors === null) {
                    echo "$template_dir is OK.\n";
                }
            }
        }
        if ($errors === null) {
            echo "Testing compile directory...\n";
        }
        // test if registered compile_dir is accessible
        $__compile_dir = $smarty->getCompileDir();
        $_compile_dir = realpath($__compile_dir);
        if (!$_compile_dir) {
            $status = false;
            $message = "FAILED: {$__compile_dir} does not exist";
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'compile_dir' ] = $message;
            }
        } elseif (!is_dir($_compile_dir)) {
            $status = false;
            $message = "FAILED: {$_compile_dir} is not a directory";
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'compile_dir' ] = $message;
            }
        } elseif (!is_readable($_compile_dir)) {
            $status = false;
            $message = "FAILED: {$_compile_dir} is not readable";
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'compile_dir' ] = $message;
            }
        } elseif (!is_writable($_compile_dir)) {
            $status = false;
            $message = "FAILED: {$_compile_dir} is not writable";
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'compile_dir' ] = $message;
            }
        } else {
            if ($errors === null) {
                echo "{$_compile_dir} is OK.\n";
            }
        }
        if ($errors === null) {
            echo "Testing plugins directory...\n";
        }
        // test if all registered plugins_dir are accessible
        // and if core plugins directory is still registered
        $_core_plugins_dir = realpath(dirname(__FILE__) . '/../plugins');
        $_core_plugins_available = false;
        foreach ($smarty->getPluginsDir() as $plugin_dir) {
            $_plugin_dir = $plugin_dir;
            $plugin_dir = realpath($plugin_dir);
            // resolve include_path or fail existence
            if (!$plugin_dir) {
                if ($smarty->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_plugin_dir)) {
                    // try PHP include_path
                    if ($_stream_resolve_include_path) {
                        $plugin_dir = stream_resolve_include_path($_plugin_dir);
                    } else {
                        $plugin_dir = $smarty->ext->_getIncludePath->getIncludePath($_plugin_dir, null, $smarty);
                    }
                    if ($plugin_dir !== false) {
                        if ($errors === null) {
                            echo "$plugin_dir is OK.\n";
                        }
                        continue;
                    } else {
                        $status = false;
                        $message = "FAILED: $_plugin_dir does not exist (and couldn't be found in include_path either)";
                        if ($errors === null) {
                            echo $message . ".\n";
                        } else {
                            $errors[ 'plugins_dir' ] = $message;
                        }
                        continue;
                    }
                } else {
                    $status = false;
                    $message = "FAILED: $_plugin_dir does not exist";
                    if ($errors === null) {
                        echo $message . ".\n";
                    } else {
                        $errors[ 'plugins_dir' ] = $message;
                    }
                    continue;
                }
            }
            if (!is_dir($plugin_dir)) {
                $status = false;
                $message = "FAILED: $plugin_dir is not a directory";
                if ($errors === null) {
                    echo $message . ".\n";
                } else {
                    $errors[ 'plugins_dir' ] = $message;
                }
            } elseif (!is_readable($plugin_dir)) {
                $status = false;
                $message = "FAILED: $plugin_dir is not readable";
                if ($errors === null) {
                    echo $message . ".\n";
                } else {
                    $errors[ 'plugins_dir' ] = $message;
                }
            } elseif ($_core_plugins_dir && $_core_plugins_dir == realpath($plugin_dir)) {
                $_core_plugins_available = true;
                if ($errors === null) {
                    echo "$plugin_dir is OK.\n";
                }
            } else {
                if ($errors === null) {
                    echo "$plugin_dir is OK.\n";
                }
            }
        }
        if (!$_core_plugins_available) {
            $status = false;
            $message = "WARNING: Smarty's own libs/plugins is not available";
            if ($errors === null) {
                echo $message . ".\n";
            } elseif (!isset($errors[ 'plugins_dir' ])) {
                $errors[ 'plugins_dir' ] = $message;
            }
        }
        if ($errors === null) {
            echo "Testing cache directory...\n";
        }
        // test if all registered cache_dir is accessible
        $__cache_dir = $smarty->getCacheDir();
        $_cache_dir = realpath($__cache_dir);
        if (!$_cache_dir) {
            $status = false;
            $message = "FAILED: {$__cache_dir} does not exist";
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'cache_dir' ] = $message;
            }
        } elseif (!is_dir($_cache_dir)) {
            $status = false;
            $message = "FAILED: {$_cache_dir} is not a directory";
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'cache_dir' ] = $message;
            }
        } elseif (!is_readable($_cache_dir)) {
            $status = false;
            $message = "FAILED: {$_cache_dir} is not readable";
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'cache_dir' ] = $message;
            }
        } elseif (!is_writable($_cache_dir)) {
            $status = false;
            $message = "FAILED: {$_cache_dir} is not writable";
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'cache_dir' ] = $message;
            }
        } else {
            if ($errors === null) {
                echo "{$_cache_dir} is OK.\n";
            }
        }
        if ($errors === null) {
            echo "Testing configs directory...\n";
        }
        // test if all registered config_dir are accessible
        foreach ($smarty->getConfigDir() as $config_dir) {
            $_config_dir = $config_dir;
            // resolve include_path or fail existence
            if (!$config_dir) {
                if ($smarty->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_config_dir)) {
                    // try PHP include_path
                    if ($_stream_resolve_include_path) {
                        $config_dir = stream_resolve_include_path($_config_dir);
                    } else {
                        $config_dir = $smarty->ext->_getIncludePath->getIncludePath($_config_dir, null, $smarty);
                    }
                    if ($config_dir !== false) {
                        if ($errors === null) {
                            echo "$config_dir is OK.\n";
                        }
                        continue;
                    } else {
                        $status = false;
                        $message = "FAILED: $_config_dir does not exist (and couldn't be found in include_path either)";
                        if ($errors === null) {
                            echo $message . ".\n";
                        } else {
                            $errors[ 'config_dir' ] = $message;
                        }
                        continue;
                    }
                } else {
                    $status = false;
                    $message = "FAILED: $_config_dir does not exist";
                    if ($errors === null) {
                        echo $message . ".\n";
                    } else {
                        $errors[ 'config_dir' ] = $message;
                    }
                    continue;
                }
            }
            if (!is_dir($config_dir)) {
                $status = false;
                $message = "FAILED: $config_dir is not a directory";
                if ($errors === null) {
                    echo $message . ".\n";
                } else {
                    $errors[ 'config_dir' ] = $message;
                }
            } elseif (!is_readable($config_dir)) {
                $status = false;
                $message = "FAILED: $config_dir is not readable";
                if ($errors === null) {
                    echo $message . ".\n";
                } else {
                    $errors[ 'config_dir' ] = $message;
                }
            } else {
                if ($errors === null) {
                    echo "$config_dir is OK.\n";
                }
            }
        }
        if ($errors === null) {
            echo "Testing sysplugin files...\n";
        }
        // test if sysplugins are available
        $source = SMARTY_SYSPLUGINS_DIR;
        if (is_dir($source)) {
            $expectedSysplugins = array(
                'smartycompilerexception.php'                               => true,
                'smartyexception.php'                                       => true,
                'smarty_cacheresource.php'                                  => true,
                'smarty_cacheresource_custom.php'                           => true,
                'smarty_cacheresource_keyvaluestore.php'                    => true,
                'smarty_data.php'                                           => true,
                'smarty_internal_block.php'                                 => true,
                'smarty_internal_cacheresource_file.php'                    => true,
                'smarty_internal_compilebase.php'                           => true,
                'smarty_internal_compile_append.php'                        => true,
                'smarty_internal_compile_assign.php'                        => true,
                'smarty_internal_compile_block.php'                         => true,
                'smarty_internal_compile_block_child.php'                   => true,
                'smarty_internal_compile_block_parent.php'                  => true,
                'smarty_internal_compile_child.php'                         => true,
                'smarty_internal_compile_parent.php'                        => true,
                'smarty_internal_compile_break.php'                         => true,
                'smarty_internal_compile_call.php'                          => true,
                'smarty_internal_compile_capture.php'                       => true,
                'smarty_internal_compile_config_load.php'                   => true,
                'smarty_internal_compile_continue.php'                      => true,
                'smarty_internal_compile_debug.php'                         => true,
                'smarty_internal_compile_eval.php'                          => true,
                'smarty_internal_compile_extends.php'                       => true,
                'smarty_internal_compile_for.php'                           => true,
                'smarty_internal_compile_foreach.php'                       => true,
                'smarty_internal_compile_function.php'                      => true,
                'smarty_internal_compile_if.php'                            => true,
                'smarty_internal_compile_include.php'                       => true,
                'smarty_internal_compile_include_php.php'                   => true,
                'smarty_internal_compile_insert.php'                        => true,
                'smarty_internal_compile_ldelim.php'                        => true,
                'smarty_internal_compile_make_nocache.php'                  => true,
                'smarty_internal_compile_nocache.php'                       => true,
                'smarty_internal_compile_private_block_plugin.php'          => true,
                'smarty_internal_compile_private_foreachsection.php'        => true,
                'smarty_internal_compile_private_function_plugin.php'       => true,
                'smarty_internal_compile_private_modifier.php'              => true,
                'smarty_internal_compile_private_object_block_function.php' => true,
                'smarty_internal_compile_private_object_function.php'       => true,
                'smarty_internal_compile_private_php.php'                   => true,
                'smarty_internal_compile_private_print_expression.php'      => true,
                'smarty_internal_compile_private_registered_block.php'      => true,
                'smarty_internal_compile_private_registered_function.php'   => true,
                'smarty_internal_compile_private_special_variable.php'      => true,
                'smarty_internal_compile_rdelim.php'                        => true,
                'smarty_internal_compile_section.php'                       => true,
                'smarty_internal_compile_setfilter.php'                     => true,
                'smarty_internal_compile_shared_inheritance.php'            => true,
                'smarty_internal_compile_while.php'                         => true,
                'smarty_internal_configfilelexer.php'                       => true,
                'smarty_internal_configfileparser.php'                      => true,
                'smarty_internal_config_file_compiler.php'                  => true,
                'smarty_internal_data.php'                                  => true,
                'smarty_internal_debug.php'                                 => true,
                'smarty_internal_errorhandler.php'                          => true,
                'smarty_internal_extension_handler.php'                     => true,
                'smarty_internal_method_addautoloadfilters.php'             => true,
                'smarty_internal_method_adddefaultmodifiers.php'            => true,
                'smarty_internal_method_append.php'                         => true,
                'smarty_internal_method_appendbyref.php'                    => true,
                'smarty_internal_method_assignbyref.php'                    => true,
                'smarty_internal_method_assignglobal.php'                   => true,
                'smarty_internal_method_clearallassign.php'                 => true,
                'smarty_internal_method_clearallcache.php'                  => true,
                'smarty_internal_method_clearassign.php'                    => true,
                'smarty_internal_method_clearcache.php'                     => true,
                'smarty_internal_method_clearcompiledtemplate.php'          => true,
                'smarty_internal_method_clearconfig.php'                    => true,
                'smarty_internal_method_compileallconfig.php'               => true,
                'smarty_internal_method_compilealltemplates.php'            => true,
                'smarty_internal_method_configload.php'                     => true,
                'smarty_internal_method_createdata.php'                     => true,
                'smarty_internal_method_getautoloadfilters.php'             => true,
                'smarty_internal_method_getconfigvariable.php'              => true,
                'smarty_internal_method_getconfigvars.php'                  => true,
                'smarty_internal_method_getdebugtemplate.php'               => true,
                'smarty_internal_method_getdefaultmodifiers.php'            => true,
                'smarty_internal_method_getglobal.php'                      => true,
                'smarty_internal_method_getregisteredobject.php'            => true,
                'smarty_internal_method_getstreamvariable.php'              => true,
                'smarty_internal_method_gettags.php'                        => true,
                'smarty_internal_method_gettemplatevars.php'                => true,
                'smarty_internal_method_literals.php'                       => true,
                'smarty_internal_method_loadfilter.php'                     => true,
                'smarty_internal_method_loadplugin.php'                     => true,
                'smarty_internal_method_mustcompile.php'                    => true,
                'smarty_internal_method_registercacheresource.php'          => true,
                'smarty_internal_method_registerclass.php'                  => true,
                'smarty_internal_method_registerdefaultconfighandler.php'   => true,
                'smarty_internal_method_registerdefaultpluginhandler.php'   => true,
                'smarty_internal_method_registerdefaulttemplatehandler.php' => true,
                'smarty_internal_method_registerfilter.php'                 => true,
                'smarty_internal_method_registerobject.php'                 => true,
                'smarty_internal_method_registerplugin.php'                 => true,
                'smarty_internal_method_registerresource.php'               => true,
                'smarty_internal_method_setautoloadfilters.php'             => true,
                'smarty_internal_method_setdebugtemplate.php'               => true,
                'smarty_internal_method_setdefaultmodifiers.php'            => true,
                'smarty_internal_method_unloadfilter.php'                   => true,
                'smarty_internal_method_unregistercacheresource.php'        => true,
                'smarty_internal_method_unregisterfilter.php'               => true,
                'smarty_internal_method_unregisterobject.php'               => true,
                'smarty_internal_method_unregisterplugin.php'               => true,
                'smarty_internal_method_unregisterresource.php'             => true,
                'smarty_internal_nocache_insert.php'                        => true,
                'smarty_internal_parsetree.php'                             => true,
                'smarty_internal_parsetree_code.php'                        => true,
                'smarty_internal_parsetree_dq.php'                          => true,
                'smarty_internal_parsetree_dqcontent.php'                   => true,
                'smarty_internal_parsetree_tag.php'                         => true,
                'smarty_internal_parsetree_template.php'                    => true,
                'smarty_internal_parsetree_text.php'                        => true,
                'smarty_internal_resource_eval.php'                         => true,
                'smarty_internal_resource_extends.php'                      => true,
                'smarty_internal_resource_file.php'                         => true,
                'smarty_internal_resource_php.php'                          => true,
                'smarty_internal_resource_registered.php'                   => true,
                'smarty_internal_resource_stream.php'                       => true,
                'smarty_internal_resource_string.php'                       => true,
                'smarty_internal_runtime_cachemodify.php'                   => true,
                'smarty_internal_runtime_cacheresourcefile.php'             => true,
                'smarty_internal_runtime_capture.php'                       => true,
                'smarty_internal_runtime_codeframe.php'                     => true,
                'smarty_internal_runtime_filterhandler.php'                 => true,
                'smarty_internal_runtime_foreach.php'                       => true,
                'smarty_internal_runtime_getincludepath.php'                => true,
                'smarty_internal_runtime_inheritance.php'                   => true,
                'smarty_internal_runtime_make_nocache.php'                  => true,
                'smarty_internal_runtime_tplfunction.php'                   => true,
                'smarty_internal_runtime_updatecache.php'                   => true,
                'smarty_internal_runtime_updatescope.php'                   => true,
                'smarty_internal_runtime_writefile.php'                     => true,
                'smarty_internal_smartytemplatecompiler.php'                => true,
                'smarty_internal_template.php'                              => true,
                'smarty_internal_templatebase.php'                          => true,
                'smarty_internal_templatecompilerbase.php'                  => true,
                'smarty_internal_templatelexer.php'                         => true,
                'smarty_internal_templateparser.php'                        => true,
                'smarty_internal_testinstall.php'                           => true,
                'smarty_internal_undefined.php'                             => true,
                'smarty_resource.php'                                       => true,
                'smarty_resource_custom.php'                                => true,
                'smarty_resource_recompiled.php'                            => true,
                'smarty_resource_uncompiled.php'                            => true,
                'smarty_security.php'                                       => true,
                'smarty_template_cached.php'                                => true,
                'smarty_template_compiled.php'                              => true,
                'smarty_template_config.php'                                => true,
                'smarty_template_resource_base.php'                         => true,
                'smarty_template_source.php'                                => true,
                'smarty_undefined_variable.php'                             => true,
                'smarty_variable.php'                                       => true,
            );
            $iterator = new DirectoryIterator($source);
            foreach ($iterator as $file) {
                if (!$file->isDot()) {
                    $filename = $file->getFilename();
                    if (isset($expectedSysplugins[ $filename ])) {
                        unset($expectedSysplugins[ $filename ]);
                    }
                }
            }
            if ($expectedSysplugins) {
                $status = false;
                $message = "FAILED: files missing from libs/sysplugins: " . join(', ', array_keys($expectedSysplugins));
                if ($errors === null) {
                    echo $message . ".\n";
                } else {
                    $errors[ 'sysplugins' ] = $message;
                }
            } elseif ($errors === null) {
                echo "... OK\n";
            }
        } else {
            $status = false;
            $message = "FAILED: " . SMARTY_SYSPLUGINS_DIR . ' is not a directory';
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'sysplugins_dir_constant' ] = $message;
            }
        }
        if ($errors === null) {
            echo "Testing plugin files...\n";
        }
        // test if core plugins are available
        $source = SMARTY_PLUGINS_DIR;
        if (is_dir($source)) {
            $expectedPlugins = array(
                'block.textformat.php'                  => true,
                'function.counter.php'                  => true,
                'function.cycle.php'                    => true,
                'function.fetch.php'                    => true,
                'function.html_checkboxes.php'          => true,
                'function.html_image.php'               => true,
                'function.html_options.php'             => true,
                'function.html_radios.php'              => true,
                'function.html_select_date.php'         => true,
                'function.html_select_time.php'         => true,
                'function.html_table.php'               => true,
                'function.mailto.php'                   => true,
                'function.math.php'                     => true,
                'modifier.capitalize.php'               => true,
                'modifier.date_format.php'              => true,
                'modifier.debug_print_var.php'          => true,
                'modifier.escape.php'                   => true,
                'modifier.mb_wordwrap.php'              => true,
                'modifier.regex_replace.php'            => true,
                'modifier.replace.php'                  => true,
                'modifier.spacify.php'                  => true,
                'modifier.truncate.php'                 => true,
                'modifiercompiler.cat.php'              => true,
                'modifiercompiler.count_characters.php' => true,
                'modifiercompiler.count_paragraphs.php' => true,
                'modifiercompiler.count_sentences.php'  => true,
                'modifiercompiler.count_words.php'      => true,
                'modifiercompiler.default.php'          => true,
                'modifiercompiler.escape.php'           => true,
                'modifiercompiler.from_charset.php'     => true,
                'modifiercompiler.indent.php'           => true,
                'modifiercompiler.lower.php'            => true,
                'modifiercompiler.noprint.php'          => true,
                'modifiercompiler.string_format.php'    => true,
                'modifiercompiler.strip.php'            => true,
                'modifiercompiler.strip_tags.php'       => true,
                'modifiercompiler.to_charset.php'       => true,
                'modifiercompiler.unescape.php'         => true,
                'modifiercompiler.upper.php'            => true,
                'modifiercompiler.wordwrap.php'         => true,
                'outputfilter.trimwhitespace.php'       => true,
                'shared.escape_special_chars.php'       => true,
                'shared.literal_compiler_param.php'     => true,
                'shared.make_timestamp.php'             => true,
                'shared.mb_str_replace.php'             => true,
                'shared.mb_unicode.php'                 => true,
                'variablefilter.htmlspecialchars.php'   => true,
            );
            $iterator = new DirectoryIterator($source);
            foreach ($iterator as $file) {
                if (!$file->isDot()) {
                    $filename = $file->getFilename();
                    if (isset($expectedPlugins[ $filename ])) {
                        unset($expectedPlugins[ $filename ]);
                    }
                }
            }
            if ($expectedPlugins) {
                $status = false;
                $message = "FAILED: files missing from libs/plugins: " . join(', ', array_keys($expectedPlugins));
                if ($errors === null) {
                    echo $message . ".\n";
                } else {
                    $errors[ 'plugins' ] = $message;
                }
            } elseif ($errors === null) {
                echo "... OK\n";
            }
        } else {
            $status = false;
            $message = "FAILED: " . SMARTY_PLUGINS_DIR . ' is not a directory';
            if ($errors === null) {
                echo $message . ".\n";
            } else {
                $errors[ 'plugins_dir_constant' ] = $message;
            }
        }
        if ($errors === null) {
            echo "Tests complete.\n";
            echo "</PRE>\n";
        }
        return $status;
    }
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    {include file="zheader_new.tpl"} {* подключили хидер *}
{literal}
<script>
	function insertKauteTmb(imgSearch){
		const imgKaute = document.querySelector("#kautesNums_"+ imgSearch +" > div > a:nth-child(2) > img").src;						
		if(imgKaute != null && imgKaute != ""){
			const pElement = document.querySelector("#kautesNums_"+ imgSearch).parentElement;
			const img = document.createElement("img");
			img.src = imgKaute;
			img.classList.add("me-2");
			img.style.position = "relative";
			img.style.float = "left";
			img.style.zIndex = "1";
			img.style.width = "100px";
			img.style.borderRadius = ".375rem";
			img.style.maxHeight = "70px";
			img.style.cursor = "pointer";
			pElement.prepend(img);
			img.addEventListener("click", function() {
				showInfo(imgSearch);
			});
		}
	}
	function filterKauteView(e){
		if(document.querySelector('tr.text-secondary.text-opacity-25').classList.contains('d-none')) {
			e.innerHTML = "Оставить только каюты в наличии";
		}
		else{
			e.innerHTML = "Показать все каюты";
		}
		document.querySelectorAll('tr.text-secondary.text-opacity-25').forEach(function(row) {
			row.classList.toggle('d-none');
		});
	}
	</script>
	{/literal}

<main class="of-h">
	<div class="container">
		<div class="row flex-column-reverse flex-lg-row">
			<aside class="col-lg-3">
				{include file="left_search_form.tpl"} {* подключили слева форму поиска круиза *}
				{* {include file="left_banner.tpl"} *}
				{if $motorsip.name == "Григорий Пирогов"}
					{include file="left_banner.tpl"}
				{/if}
				{include file="left_info.tpl"}
			</aside>
			<section class="col-lg-9">
				{* <ol class="breadcrumb">
					<li class="breadcrumb-item"><a href="#">Главная</a></li>
					<li class="breadcrumb-item"><a href="#">Категория</a></li>
					<li class="breadcrumb-item active">Агенствам</li>
				</ol> *}
				{*	{include file="breadcrumb.tpl"}  подключили хлебные крошки *}
				<h1 class="s-title">Забронировать круиз по маршруту</h1>
				{* <div class="marsh-title">
					Маршрут рейса:
				</div> *}
				<div class="marsh">
					<svg xmlns="http://www.w3.org/2000/svg" class="me-3" viewBox="0 0 512 512" width="32" height="32"
						fill="rgb(44, 175, 233)">
						<path
							d="M416 256s96-96 96-160c0-53-43-96-96-96s-96 43-96 96c0 29.4 20.2 65.5 42.1 96H320c-53 0-96 43-96 96s43 96 96 96h96c17.7 0 32 14.3 32 32s-14.3 32-32 32H188.6c-6.2 9.6-12.6 18.8-19 27.2c-10.7 14.2-21.3 26.9-30 36.8H416c53 0 96-43 96-96s-43-96-96-96H320c-17.7 0-32-14.3-32-32s14.3-32 32-32h96zm0-128c-17.7 0-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32s-14.3 32-32 32zM149.9 448c21.9-30.5 42.1-66.6 42.1-96c0-53-43-96-96-96s-96 43-96 96c0 64 96 160 96 160s3.5-3.5 9.2-9.6c.4-.4 .7-.8 1.1-1.2c3.3-3.5 7.1-7.8 11.4-12.8c.2-.2 .4-.4 .6-.6c9.4-10.8 20.7-24.6 31.6-39.8zM96 384c-17.7 0-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32s-14.3 32-32 32z" />
					</svg>
					<span class="text-danger fw-bold me-3">{$dateReis.marshrut_name}</span> {$marshBig}
				</div>
				<div class="dates">
					<div class="d-block">
						<div class="dates-title">
							Отправление:
						</div>
						<div class="date text-center">
							<span
								class="topDate me-3">{$dateReis.dateStart|date_format:"%d.%m.%Y"}</span>&nbsp;&nbsp;{$dateReis.timeStart|date_format:"%H:%M"}
						</div>
					</div>
					<div class="d-block">
						<div class="dates-title">
							Прибытие:
						</div>
						<div class="date text-center">
							<span
								class="topDate me-3">{$dateReis.dateEnd|date_format:"%d.%m.%Y"}</span>&nbsp;&nbsp;{$dateReis.timeEnd|date_format:"%H:%M"}
						</div>
					</div>

					<div>
						<div class="dates-title">
							Продолжительность:
						</div>
						<div class="date text-center">
							{$dateReis.dlit} дн.
						</div>
					</div>
				</div>

				{* <div class="teplohod d-block">
					<div>
						<div class="dates-title">
							Теплоход:
						</div>

							<a data-toggle="collapse" href="javascript:void();" data-target="#collapseExample" role="button" aria-expanded="false"
								aria-controls="collapseExample" class="date d-block tog smaa" id="mtsName">

							</a>

					</div>
				</div> *}
				<div class="mb-4">
					<div class="teplohod-box article p-4">
						<div style="position: relative;" class="row d-flex justify-content-center">
							<h2 class="s-title">Круиз на т/х &laquo;{$motorsip.name}&raquo;
								{if $motorsip.name == "Россия"}
									<img src="https://{$smarty.server.SERVER_NAME}/assets/img/newicon.svg" width="48px" title="Новинка">
								{/if}
							</h2>
							{if $motorsip.shipAction != ""}
								<h4 style="color:red;" class="text-center">{$motorsip.shipAction}</h4>
							{/if}
							<div class="row shipTextHide" id="collapseExample">
								<div class="col-md-1 col-lg-2 d-none d-md-flex">&nbsp;</div>
								<div class="col-12 col-md-10 col-lg-8 shipslider-for mGallery mb-5 align-self-center">
									{foreach $ship_photo as $sphoto}
										<div>
											<a class="image-popup image-magnific" href="https://{$smarty.server.SERVER_NAME}{$sphoto.kp_path}"
												title="Фото интерьера и экстерьера лайнера"><img {if {$sphoto@iteration}> 1 }
													src="https://{$smarty.server.SERVER_NAME}{$sphoto.kp_path}" alt="" width="100%" height="100%">
												{else}
													src="https://{$smarty.server.SERVER_NAME}{$sphoto.kp_path}" alt="" width="100%" height="100%">
												{/if}
											</a>
										</div>
									{/foreach}
								</div>
								<div class="col-md-1 col-lg-2 d-none d-md-flex">&nbsp;</div>
								{* <div class="col-md-1 d-none d-md-flex">&nbsp;</div>  col-12 col-md-10*}

								<div class="shipslider-nav mt-2 mb-5" id="sliderRow">
									{foreach $ship_photo as $sphoto}
										<div>
											<img data-lazy="https://{$smarty.server.SERVER_NAME}{$sphoto.kp_thumb_path}" alt="" width="93px"
												height="60px">
										</div>
									{/foreach}
								</div>
								{* <span class="popWrapp">
									<span class="alert alert-light popContent">Раскрыть информацию о теплоходе</span>
								</span> *}
								<span class="date d-block smaa">
									<svg version="1.1" id="Icons" xmlns="ht