User talk:Zs6ro
From FollowTheScore
Expr.php:
<?php if ( !defined( 'MEDIAWIKI' ) ) { die( 'This file is a MediaWiki extension, it is not a valid entry point' ); } // Character classes define( 'EXPR_WHITE_CLASS', " \t\r\n" ); define( 'EXPR_NUMBER_CLASS', '0123456789.' ); // Token types define( 'EXPR_WHITE', 1 ); define( 'EXPR_NUMBER', 2 ); define( 'EXPR_NEGATIVE', 3 ); define( 'EXPR_POSITIVE', 4 ); define( 'EXPR_PLUS', 5 ); define( 'EXPR_MINUS', 6 ); define( 'EXPR_TIMES', 7 ); define( 'EXPR_DIVIDE', 8 ); define( 'EXPR_MOD', 9 ); define( 'EXPR_OPEN', 10 ); define( 'EXPR_CLOSE', 11 ); define( 'EXPR_AND', 12 ); define( 'EXPR_OR', 13 ); define( 'EXPR_NOT', 14 ); define( 'EXPR_EQUALITY', 15 ); define( 'EXPR_LESS', 16 ); define( 'EXPR_GREATER', 17 ); define( 'EXPR_LESSEQ', 18 ); define( 'EXPR_GREATEREQ', 19 ); define( 'EXPR_NOTEQ', 20 ); define( 'EXPR_ROUND', 21 ); define( 'EXPR_INT_DIVIDE', 22); define( 'EXPR_CEIL', 23); define( 'EXPR_FLOOR', 24); define( 'EXPR_ABS', 25); define( 'EXPR_FLOAT_MOD', 26); define( 'EXPR_POW', 27); define( 'EXPR_SQRT', 28); define( 'EXPR_E', 29); class ExprError extends Exception { public function __construct($msg, $parameter = ''){ $this->message = wfMsgForContent( "expr_$msg", htmlspecialchars( $parameter ) ); } } class ExprParser { var $maxStackSize = 100; var $precedence = array( EXPR_NEGATIVE => 10, EXPR_POSITIVE => 10, EXPR_E => 10, EXPR_NOT => 9, EXPR_ABS => 9, EXPR_CEIL => 9, EXPR_FLOOR => 9, EXPR_POW => 9, EXPR_SQRT => 9, EXPR_TIMES => 8, EXPR_DIVIDE => 8, EXPR_INT_DIVIDE => 8, EXPR_MOD => 8, EXPR_FLOAT_MOD => 8, EXPR_PLUS => 6, EXPR_MINUS => 6, EXPR_ROUND => 5, EXPR_EQUALITY => 4, EXPR_LESS => 4, EXPR_GREATER => 4, EXPR_LESSEQ => 4, EXPR_GREATEREQ => 4, EXPR_NOTEQ => 4, EXPR_AND => 3, EXPR_OR => 2, EXPR_OPEN => -1, EXPR_CLOSE => -1 ); var $names = array( EXPR_NEGATIVE => '-', EXPR_POSITIVE => '+', EXPR_NOT => 'not', EXPR_TIMES => '*', EXPR_DIVIDE => '/', EXPR_MOD => 'mod', EXPR_FLOAT_MOD => 'fmod', EXPR_PLUS => '+', EXPR_MINUS => '-', EXPR_ROUND => 'round', EXPR_EQUALITY => '=', EXPR_LESS => '<', EXPR_GREATER => '>', EXPR_LESSEQ => '<=', EXPR_GREATEREQ => '>=', EXPR_NOTEQ => '<>', EXPR_AND => 'and', EXPR_OR => 'or', EXPR_INT_DIVIDE => 'idiv', EXPR_ABS => 'abs', EXPR_CEIL => 'ceil', EXPR_FLOOR => 'floor', EXPR_POW => '^', EXPR_SQRT => 'sqrt', EXPR_E => 'e', ); var $words = array( 'mod' => EXPR_MOD, 'and' => EXPR_AND, 'or' => EXPR_OR, 'not' => EXPR_NOT, 'round' => EXPR_ROUND, 'div' => EXPR_DIVIDE, 'idiv' => EXPR_INT_DIVIDE, 'floor' => EXPR_FLOOR, 'ceil' => EXPR_CEIL, 'abs' => EXPR_ABS, 'fmod' => EXPR_FLOAT_MOD, 'sqrt' => EXPR_SQRT, 'e' => EXPR_E, ); /** * Add expression messages to the message cache * @static */ function addMessages() { global $wgMessageCache; $wgMessageCache->addMessages( array( 'expr_stack_exhausted' => 'Expression error: Stack exhausted', 'expr_unexpected_number' => 'Expression error: Unexpected number', 'expr_preg_match_failure' => 'Expression error: Unexpected preg_match failure', 'expr_unrecognised_word' => 'Expression error: Unrecognised word "$1"', 'expr_unexpected_operator' => 'Expression error: Unexpected $1 operator', 'expr_missing_operand' => 'Expression error: Missing operand for $1', 'expr_unexpected_closing_bracket' => 'Expression error: Unexpected closing bracket', 'expr_unrecognised_punctuation' => 'Expression error: Unrecognised punctuation character "$1"', 'expr_unclosed_bracket' => 'Expression error: Unclosed bracket', 'expr_division_by_zero' => 'Division by zero', 'expr_unknown_error' => 'Expression error: Unknown error ($1)', 'expr_not_a_number' => 'In $1: result is not a number', )); } /** * Evaluate a mathematical expression * * The algorithm here is based on the infix to RPN algorithm given in * http://montcs.bloomu.edu/~bobmon/Information/RPN/infix2rpn.shtml * It's essentially the same as Dijkstra's shunting yard algorithm. */ function doExpression( $expr ) { $operands = array(); $operators = array(); # Unescape inequality operators $expr = strtr( $expr, array( '<' => '<', '>' => '>' ) ); $p = 0; $end = strlen( $expr ); $expecting = 'expression'; while ( $p < $end ) { if ( count( $operands ) > $this->maxStackSize || count( $operators ) > $this->maxStackSize ) { throw new ExprError('stack_exhausted'); } $char = $expr[$p]; $char2 = substr( $expr, $p, 2 ); // Mega if-elseif-else construct // Only binary operators fall through for processing at the bottom, the rest // finish their processing and continue // First the unlimited length classes if ( false !== strpos( EXPR_WHITE_CLASS, $char ) ) { // Whitespace $p += strspn( $expr, EXPR_WHITE_CLASS, $p ); continue; } elseif ( false !== strpos( EXPR_NUMBER_CLASS, $char ) ) { // Number if ( $expecting != 'expression' ) { throw new ExprError('unexpected_number'); } // Find the rest of it $length = strspn( $expr, EXPR_NUMBER_CLASS, $p ); // Convert it to float, silently removing double decimal points $operands[] = floatval( substr( $expr, $p, $length ) ); $p += $length; $expecting = 'operator'; continue; } elseif ( ctype_alpha( $char ) ) { // Word // Find the rest of it $remaining = substr( $expr, $p ); if ( !preg_match( '/^[A-Za-z]*/', $remaining, $matches ) ) { // This should be unreachable throw new ExprError('preg_match_failure'); } $word = strtolower( $matches[0] ); $p += strlen( $word ); // Interpret the word if ( !isset( $this->words[$word] ) ){ throw new ExprError('unrecognised_word', $word); } $op = $this->words[$word]; // Unary operator switch($op){ case EXPR_NOT: case EXPR_CEIL: case EXPR_FLOOR: case EXPR_ABS: case EXPR_SQRT: if ( $expecting != 'expression' ) { throw new ExprError('unexpected_operator', $word); } $operators[] = $op; continue 2; } // Binary operator, fall through $name = $word; } // Next the two-character operators elseif ( $char2 == '<=' ) { $name = $char2; $op = EXPR_LESSEQ; $p += 2; } elseif ( $char2 == '>=' ) { $name = $char2; $op = EXPR_GREATEREQ; $p += 2; } elseif ( $char2 == '<>' || $char2 == '!=' ) { $name = $char2; $op = EXPR_NOTEQ; $p += 2; } // Finally the single-character operators elseif ( $char == '+' ) { ++$p; if ( $expecting == 'expression' ) { // Unary plus $operators[] = EXPR_POSITIVE; continue; } else { // Binary plus $op = EXPR_PLUS; } } elseif ( $char == '-' ) { ++$p; if ( $expecting == 'expression' ) { // Unary minus $operators[] = EXPR_NEGATIVE; continue; } else { // Binary minus $op = EXPR_MINUS; } } elseif ( $char == '*' ) { $name = $char; $op = EXPR_TIMES; ++$p; } elseif ( $char == '/' ) { $name = $char; $op = EXPR_DIVIDE; ++$p; } elseif ( $char == '(' ) { if ( $expecting == 'operator' ) { throw new ExprError('unexpected_operator', '('); } $operators[] = EXPR_OPEN; ++$p; continue; } elseif ( $char == ')' ) { $lastOp = end( $operators ); while ( $lastOp && $lastOp != EXPR_OPEN ) { $this->doOperation( $lastOp, $operands ); array_pop( $operators ); $lastOp = end( $operators ); } if ( $lastOp ) { array_pop( $operators ); } else { throw new ExprError('unexpected_closing_bracket'); } $expecting = 'operator'; ++$p; continue; } elseif ( $char == '=' ) { $name = $char; $op = EXPR_EQUALITY; ++$p; } elseif ( $char == '<' ) { $name = $char; $op = EXPR_LESS; ++$p; } elseif ( $char == '>' ) { $name = $char; $op = EXPR_GREATER; ++$p; } elseif ( $char == '^' ) { $name = $char; $op = EXPR_POW; ++$p; } else { throw new ExprError('unrecognised_punctuation', $char); } // Binary operator processing if ( $expecting == 'expression' ) { throw new ExprError('unexpected_operator', $name); } // Shunting yard magic $lastOp = end( $operators ); while ( $lastOp && $this->precedence[$op] <= $this->precedence[$lastOp] ) { $this->doOperation( $lastOp, $operands ); array_pop( $operators ); $lastOp = end( $operators ); } $operators[] = $op; $expecting = 'expression'; } // Finish off the operator array while ( $op = array_pop( $operators ) ) { if ( $op == EXPR_OPEN ) { throw new ExprError('unclosed_bracket'); } $this->doOperation( $op, $operands ); } return implode( "<br />\n", $operands ); } function doOperation( $op, &$stack ) { switch ( $op ) { case EXPR_NEGATIVE: if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); $arg = array_pop( $stack ); $stack[] = -$arg; break; case EXPR_POSITIVE: if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); break; case EXPR_TIMES: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = $left * $right; break; case EXPR_DIVIDE: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); if ( $right == 0 ) throw new ExprError('division_by_zero', $this->names[$op]); $stack[] = $left / $right; break; case EXPR_MOD: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); if ( $right == 0 ) throw new ExprError('division_by_zero', $this->names[$op]); $stack[] = $left % $right; break; case EXPR_PLUS: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = $left + $right; break; case EXPR_MINUS: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = $left - $right; break; case EXPR_AND: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = ( $left && $right ) ? 1 : 0; break; case EXPR_OR: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = ( $left || $right ) ? 1 : 0; break; case EXPR_EQUALITY: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = ( $left == $right ) ? 1 : 0; break; case EXPR_NOT: if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); $arg = array_pop( $stack ); $stack[] = (!$arg) ? 1 : 0; break; case EXPR_ROUND: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $digits = intval( array_pop( $stack ) ); $value = array_pop( $stack ); $stack[] = round( $value, $digits ); break; case EXPR_LESS: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = ( $left < $right ) ? 1 : 0; break; case EXPR_GREATER: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = ( $left > $right ) ? 1 : 0; break; case EXPR_LESSEQ: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = ( $left <= $right ) ? 1 : 0; break; case EXPR_GREATEREQ: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = ( $left >= $right ) ? 1 : 0; break; case EXPR_NOTEQ: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $stack[] = ( $left != $right ) ? 1 : 0; break; case EXPR_ABS: if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); $arg = array_pop( $stack ); $stack[] = abs($arg); break; case EXPR_CEIL: if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); $arg = array_pop( $stack ); $stack[] = ceil($arg); break; case EXPR_FLOOR: if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); $arg = array_pop( $stack ); $stack[] = floor($arg); break; case EXPR_E: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); // can never be NaN $stack[] = $left * pow(10,$right); break; case EXPR_POW: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); $result = pow($left,$right); if (is_nan($result)) throw new ExprError('not_a_number', $this->names[$op]); $stack[] = $result; break; case EXPR_FLOAT_MOD: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); if ( $right == 0 ) throw new ExprError('division_by_zero', $this->names[$op]); $stack[] = fmod($left,$right); break; case EXPR_SQRT: if ( count( $stack ) < 1 ) throw new ExprError('missing_operand', $this->names[$op]); $arg = array_pop( $stack ); $result = sqrt($arg); if (is_nan($result)) throw new ExprError('not_a_number', $this->names[$op]); $stack[] = $result; break; case EXPR_INT_DIVIDE: if ( count( $stack ) < 2 ) throw new ExprError('missing_operand', $this->names[$op]); $right = array_pop( $stack ); $left = array_pop( $stack ); if ( $right == 0 ) throw new ExprError('division_by_zero', $this->names[$op]); $stack[] = (int)($left / $right); break; default: // Should be impossible to reach here. throw new ExprError('unknown_error'); } } } ?>
ParserFunctions.php
<?php if ( !defined( 'MEDIAWIKI' ) ) { die( 'This file is a MediaWiki extension, it is not a valid entry point' ); } $wgExtensionFunctions[] = 'wfSetupParserFunctions'; define('PARSER_FUNCTIONS_VERSION', '?'); /* !! This will break Special:Version !! $wgExtensionCredits['parserhook'][] = array( 'name' => 'ParserFunctions (extended)', 'author' => 'Tim Starling, Carl Fürstenberg (AzaToth)', 'url' => 'http://meta.wikimedia.org/wiki/ParserFunctions', 'description' => 'Enhance parser with mathematical and logical functions', 'version' => PARSER_FUNCTIONS_VERSION, ); */ $wgHooks['LanguageGetMagic'][] = 'wfParserFunctionsLanguageGetMagic'; class ExtParserFunctions { var $mExprParser; var $mTimeCache = array(); var $mTimeChars = 0; var $mMaxTimeChars = 6000; # ~10 seconds function clearState() { $this->mTimeChars = 0; return true; } function &getExprParser() { if ( !isset( $this->mExpr ) ) { if ( !class_exists( 'ExprParser' ) ) { require( dirname( __FILE__ ) . '/Expr.php' ); ExprParser::addMessages(); } $this->mExprParser = new ExprParser; } return $this->mExprParser; } function expr( &$parser, $expr = '' ) { try { return $this->getExprParser()->doExpression( $expr ); } catch(ExprError $e) { return $e->getMessage(); } } function maxHook(&$parser) { try { $args = func_get_args(); array_shift( $args ); $exprParser = $this->getExprParser(); foreach($args as $expr){ $res = $exprParser->doExpression($expr); $result[] = $res; } return max($result); } catch(ExprError $e) { return $e->getMessage(); } } function minHook(&$parser) { try { $args = func_get_args(); array_shift( $args ); $exprParser = $this->getExprParser(); foreach($args as $expr){ $res = $exprParser->doExpression($expr); $result[] = $res; } return min($result); } catch(ExprError $e) { return $e->getMessage(); } } function ifexpr( &$parser, $expr = '', $then = '', $else = '' ) { try{ if($this->getExprParser()->doExpression( $expr )) { return $then; } else { return $else; } } catch (ExprError $e){ return $e->getMessage(); } } function ifHook( &$parser, $test = '', $then = '', $else = '' ) { if ( $test !== '' ) { return $then; } else { return $else; } } function ifeq( &$parser, $left = '', $right = '', $then = '', $else = '' ) { if ( $left == $right ) { return $then; } else { return $else; } } function switchHook( &$parser /*,...*/ ) { $args = func_get_args(); array_shift( $args ); $value = trim(array_shift($args)); $found = false; $parts = null; $default = null; foreach( $args as $arg ) { $parts = array_map( 'trim', explode( '=', $arg, 2 ) ); if ( count( $parts ) == 2 ) { if ( $found || $parts[0] == $value ) { return $parts[1]; } else { $mwDefault =& MagicWord::get( 'default' ); if ( $mwDefault->matchStartAndRemove( $parts[0] ) ) { $default = $parts[1]; } # else wrong case, continue } } elseif ( count( $parts ) == 1 ) { # Multiple input, single output # If the value matches, set a flag and continue if ( $parts[0] == $value ) { $found = true; } } # else RAM corruption due to cosmic ray? } # Default case # Check if the last item had no = sign, thus specifying the default case if ( count( $parts ) == 1) { return $parts[0]; } elseif ( !is_null( $default ) ) { return $default; } else { return ''; } } /** * Returns the absolute path to a subpage, relative to the current article * title. Treats titles as slash-separated paths. * * Following subpage link syntax instead of standard path syntax, an * initial slash is treated as a relative path, and vice versa. */ public function rel2abs( &$parser , $to = '' , $from = '' ) { $from = trim($from); if( $from == '' ) { $from = $parser->mTitle->getPrefixedText(); } $to = rtrim( $to , ' /' ); // if we have an empty path, or just one containing a dot if( $to == '' || $to == '.' ) { return $from; } // if the path isn't relative if ( substr( $to , 0 , 1) != '/' && substr( $to , 0 , 2) != './' && substr( $to , 0 , 3) != '../' && $to != '..' ) { $from = ''; } // Make a long path, containing both, enclose it in /.../ $fullPath = '/' . $from . '/' . $to . '/'; // remove redundant current path dots $fullPath = preg_replace( '!/(\./)+!', '/', $fullPath ); // remove double slashes $fullPath = preg_replace( '!/{2,}!', '/', $fullPath ); // remove the enclosing slashes now $fullPath = trim( $fullPath , '/' ); $exploded = explode ( '/' , $fullPath ); $newExploded = array(); foreach ( $exploded as $current ) { if( $current == '..' ) { // removing one level if( !count( $newExploded ) ){ // attempted to access a node above root node return wfMsgForContent( 'pfunc_rel2abs_invalid_depth', $fullPath ); } // remove last level from the stack array_pop( $newExploded ); } else { // add the current level to the stack $newExploded[] = $current; } } // we can now join it again return implode( '/' , $newExploded ); } function ifexist( &$parser, $title = '', $then = '', $else = '' ) { $title = Title::newFromText( $title ); return is_object( $title ) && $title->exists() ? $then : $else; } function time( &$parser, $format = '', $date = '' ) { global $wgContLang; if ( isset( $this->mTimeCache[$format][$date] ) ) { return $this->mTimeCache[$format][$date]; } if ( $date !== '' ) { $unix = @strtotime( $date ); } else { $unix = time(); } if ( $unix == -1 || $unix == false ) { $result = wfMsgForContent( 'pfunc_time_error' ); } else { $this->mTimeChars += strlen( $format ); if ( $this->mTimeChars > $this->mMaxTimeChars ) { return wfMsgForContent( 'pfunc_time_too_long' ); } else { $ts = wfTimestamp( TS_MW, $unix ); if ( method_exists( $wgContLang, 'sprintfDate' ) ) { $result = $wgContLang->sprintfDate( $format, $ts ); } else { if ( !class_exists( 'SprintfDateCompat' ) ) { require( dirname( __FILE__ ) . '/SprintfDateCompat.php' ); } $result = SprintfDateCompat::sprintfDate( $format, $ts ); } } } $this->mTimeCache[$format][$date] = $result; return $result; } } function wfSetupParserFunctions() { global $wgParser, $wgMessageCache, $wgExtParserFunctions, $wgMessageCache, $wgHooks; $wgExtParserFunctions = new ExtParserFunctions; $wgParser->setFunctionHook( 'expr', array( &$wgExtParserFunctions, 'expr' ) ); $wgParser->setFunctionHook( 'if', array( &$wgExtParserFunctions, 'ifHook' ) ); $wgParser->setFunctionHook( 'ifeq', array( &$wgExtParserFunctions, 'ifeq' ) ); $wgParser->setFunctionHook( 'ifexpr', array( &$wgExtParserFunctions, 'ifexpr' ) ); $wgParser->setFunctionHook( 'switch', array( &$wgExtParserFunctions, 'switchHook' ) ); $wgParser->setFunctionHook( 'ifexist', array( &$wgExtParserFunctions, 'ifexist' ) ); $wgParser->setFunctionHook( 'time', array( &$wgExtParserFunctions, 'time' ) ); $wgParser->setFunctionHook( 'max', array( &$wgExtParserFunctions, 'maxHook' ) ); $wgParser->setFunctionHook( 'min', array( &$wgExtParserFunctions, 'minHook' ) ); $wgParser->setFunctionHook( 'rel2abs', array( &$wgExtParserFunctions, 'rel2abs' ) ); $wgMessageCache->addMessage( 'pfunc_time_error', "Error: invalid time" ); $wgMessageCache->addMessage( 'pfunc_time_too_long', "Error: too many #time calls" ); $wgMessageCache->addMessage( 'pfunc_rel2abs_invalid_depth', "Error: Invalid depth in path: \"$1\" (tried to access a node above the root node)" ); $wgHooks['ParserClearState'][] = array( &$wgExtParserFunctions, 'clearState' ); } function wfParserFunctionsLanguageGetMagic( &$magicWords, $langCode ) { switch ( $langCode ) { case 'he': $magicWords['expr'] = array( 0, '???', 'expr' ); $magicWords['if'] = array( 0, '????', 'if' ); $magicWords['ifeq'] = array( 0, '????', 'ifeq' ); $magicWords['ifexpr'] = array( 0, '??? ????', 'ifexpr' ); $magicWords['switch'] = array( 0, '???', 'switch' ); $magicWords['default'] = array( 0, '#????? ????', '#default' ); $magicWords['ifexist'] = array( 0, '????', 'ifexist' ); $magicWords['time'] = array( 0, '???', 'time' ); $magicWords['rel2abs'] = array( 0, '???? ??????', 'rel2abs' ); break; default: $magicWords['expr'] = array( 0, 'expr' ); $magicWords['if'] = array( 0, 'if' ); $magicWords['ifeq'] = array( 0, 'ifeq' ); $magicWords['ifexpr'] = array( 0, 'ifexpr' ); $magicWords['switch'] = array( 0, 'switch' ); $magicWords['default'] = array( 0, '#default' ); $magicWords['ifexist'] = array( 0, 'ifexist' ); $magicWords['time'] = array( 0, 'time' ); $magicWords['max'] = array( 0, 'max' ); $magicWords['min'] = array( 0, 'min' ); $magicWords['rel2abs'] = array( 0, 'rel2abs' ); } return true; } ?>