User talk:Zs6ro

From FollowTheScore
Jump to: navigation, search

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;
}
?>