r80666 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r80665‎ | r80666 | r80667 >
Date:00:03, 21 January 2011
Author:tparscal
Status:ok
Tags:
Comment:
Addresses issues raised in an excellent review of r80656.
Modified paths:
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/libs/JavaScriptDistiller.php (modified) (history)
  • /trunk/phase3/includes/libs/ParseMaster.php (deleted) (history)

Diff [purge]

Index: trunk/phase3/includes/libs/ParseMaster.php
@@ -1,214 +0,0 @@
2 -<?php
3 -/**
4 - * ParseMaster, version 1.0.2 (2005-08-19) Copyright 2005, Dean Edwards
5 - * A multi-pattern parser.
6 - * License: http://creativecommons.org/licenses/LGPL/2.1/
7 - *
8 - * This is the PHP version of the ParseMaster component of Dean Edwards' (http://dean.edwards.name/)
9 - * Packer, which was originally written in JavaScript. It was ported to PHP by Nicolas Martin.
10 - *
11 - * Original Source: http://joliclic.free.fr/php/javascript-packer/en/
12 - *
13 - * Changes should be pushed back upstream.
14 - */
15 -class ParseMaster {
16 - public $ignoreCase = false;
17 - public $escapeChar = '';
18 -
19 - // constants
20 - const EXPRESSION = 0;
21 - const REPLACEMENT = 1;
22 - const LENGTH = 2;
23 -
24 - // used to determine nesting levels
25 - private $GROUPS = '/\\(/';//g
26 - private $SUB_REPLACE = '/\\$\\d/';
27 - private $INDEXED = '/^\\$\\d+$/';
28 - private $TRIM = '/([\'"])\\1\\.(.*)\\.\\1\\1$/';
29 - private $ESCAPE = '/\\\./';//g
30 - private $QUOTE = '/\'/';
31 - private $DELETED = '/\\x01[^\\x01]*\\x01/';//g
32 -
33 - public function add($expression, $replacement = '') {
34 - // count the number of sub-expressions
35 - // - add one because each pattern is itself a sub-expression
36 - $length = 1 + preg_match_all($this->GROUPS, $this->_internalEscape((string)$expression), $out);
37 -
38 - // treat only strings $replacement
39 - if (is_string($replacement)) {
40 - // does the pattern deal with sub-expressions?
41 - if (preg_match($this->SUB_REPLACE, $replacement)) {
42 - // a simple lookup? (e.g. "$2")
43 - if (preg_match($this->INDEXED, $replacement)) {
44 - // store the index (used for fast retrieval of matched strings)
45 - $replacement = (int)(substr($replacement, 1)) - 1;
46 - } else { // a complicated lookup (e.g. "Hello $2 $1")
47 - // build a function to do the lookup
48 - $quote = preg_match($this->QUOTE, $this->_internalEscape($replacement))
49 - ? '"' : "'";
50 - $replacement = array(
51 - 'fn' => '_backReferences',
52 - 'data' => array(
53 - 'replacement' => $replacement,
54 - 'length' => $length,
55 - 'quote' => $quote
56 - )
57 - );
58 - }
59 - }
60 - }
61 - // pass the modified arguments
62 - if (!empty($expression)) $this->_add($expression, $replacement, $length);
63 - else $this->_add('/^$/', $replacement, $length);
64 - }
65 -
66 - public function exec($string) {
67 - // execute the global replacement
68 - $this->_escaped = array();
69 -
70 - // simulate the _patterns.toSTring of Dean
71 - $regexp = '/';
72 - foreach ($this->_patterns as $reg) {
73 - $regexp .= '(' . substr($reg[self::EXPRESSION], 1, -1) . ')|';
74 - }
75 - $regexp = substr($regexp, 0, -1) . '/';
76 - $regexp .= ($this->ignoreCase) ? 'i' : '';
77 -
78 - $string = $this->_escape($string, $this->escapeChar);
79 - $string = preg_replace_callback(
80 - $regexp,
81 - array(
82 - &$this,
83 - '_replacement'
84 - ),
85 - $string
86 - );
87 - $string = $this->_unescape($string, $this->escapeChar);
88 -
89 - return preg_replace($this->DELETED, '', $string);
90 - }
91 -
92 - public function reset() {
93 - // clear the patterns collection so that this object may be re-used
94 - $this->_patterns = array();
95 - }
96 -
97 - // private
98 - private $_escaped = array(); // escaped characters
99 - private $_patterns = array(); // patterns stored by index
100 -
101 - // create and add a new pattern to the patterns collection
102 - private function _add() {
103 - $arguments = func_get_args();
104 - $this->_patterns[] = $arguments;
105 - }
106 -
107 - // this is the global replace function (it's quite complicated)
108 - private function _replacement($arguments) {
109 - if (empty($arguments)) return '';
110 -
111 - $i = 1; $j = 0;
112 - // loop through the patterns
113 - while (isset($this->_patterns[$j])) {
114 - $pattern = $this->_patterns[$j++];
115 - // do we have a result?
116 - if (isset($arguments[$i]) && ($arguments[$i] != '')) {
117 - $replacement = $pattern[self::REPLACEMENT];
118 -
119 - if (is_array($replacement) && isset($replacement['fn'])) {
120 -
121 - if (isset($replacement['data'])) $this->buffer = $replacement['data'];
122 - return call_user_func(array(&$this, $replacement['fn']), $arguments, $i);
123 -
124 - } elseif (is_int($replacement)) {
125 - return $arguments[$replacement + $i];
126 -
127 - }
128 - $delete = ($this->escapeChar == '' ||
129 - strpos($arguments[$i], $this->escapeChar) === false)
130 - ? '' : "\x01" . $arguments[$i] . "\x01";
131 - return $delete . $replacement;
132 -
133 - // skip over references to sub-expressions
134 - } else {
135 - $i += $pattern[self::LENGTH];
136 - }
137 - }
138 - }
139 -
140 - private function _backReferences($match, $offset) {
141 - $replacement = $this->buffer['replacement'];
142 - $quote = $this->buffer['quote'];
143 - $i = $this->buffer['length'];
144 - while ($i) {
145 - $replacement = str_replace('$'.$i--, $match[$offset + $i], $replacement);
146 - }
147 - return $replacement;
148 - }
149 -
150 - private function _replace_name($match, $offset){
151 - $length = strlen($match[$offset + 2]);
152 - $start = $length - max($length - strlen($match[$offset + 3]), 0);
153 - return substr($match[$offset + 1], $start, $length) . $match[$offset + 4];
154 - }
155 -
156 - private function _replace_encoded($match, $offset) {
157 - return $this->buffer[$match[$offset]];
158 - }
159 -
160 -
161 - // php : we cannot pass additional data to preg_replace_callback,
162 - // and we cannot use &$this in create_function, so let's go to lower level
163 - private $buffer;
164 -
165 - // encode escaped characters
166 - private function _escape($string, $escapeChar) {
167 - if ($escapeChar) {
168 - $this->buffer = $escapeChar;
169 - return preg_replace_callback(
170 - '/\\' . $escapeChar . '(.)' .'/',
171 - array(&$this, '_escapeBis'),
172 - $string
173 - );
174 -
175 - } else {
176 - return $string;
177 - }
178 - }
179 - private function _escapeBis($match) {
180 - $this->_escaped[] = $match[1];
181 - return $this->buffer;
182 - }
183 -
184 - // decode escaped characters
185 - private function _unescape($string, $escapeChar) {
186 - if ($escapeChar) {
187 - $regexp = '/'.'\\'.$escapeChar.'/';
188 - $this->buffer = array('escapeChar'=> $escapeChar, 'i' => 0);
189 - return preg_replace_callback
190 - (
191 - $regexp,
192 - array(&$this, '_unescapeBis'),
193 - $string
194 - );
195 -
196 - } else {
197 - return $string;
198 - }
199 - }
200 - private function _unescapeBis() {
201 - if (isset($this->_escaped[$this->buffer['i']])
202 - && $this->_escaped[$this->buffer['i']] != '')
203 - {
204 - $temp = $this->_escaped[$this->buffer['i']];
205 - } else {
206 - $temp = '';
207 - }
208 - $this->buffer['i']++;
209 - return $this->buffer['escapeChar'] . $temp;
210 - }
211 -
212 - private function _internalEscape($string) {
213 - return preg_replace($this->ESCAPE, '', $string);
214 - }
215 -}
Index: trunk/phase3/includes/libs/JavaScriptDistiller.php
@@ -16,12 +16,69 @@
1717 * JSMin::minify, this produces < 1% larger output (after gzip) in approx. 25% of the time.
1818 *
1919 * @param $script String: JavaScript code to minify
 20+ * @param $stripVerticalSpace Boolean: Try to remove as much vertical whitespace as possible
2021 */
21 - public static function stripWhiteSpace( $script, $collapseVertical = false ) {
22 - // This parser is based on regular expressions, which all get or'd together, so rules take
23 - // precedence in the order they are added. We can use it to minify by armoring certain
24 - // regions by matching them and replacing them with the full match, leaving the remaining
25 - // regions around for further matching and replacing.
 22+ public static function stripWhiteSpace( $script, $stripVerticalSpace = false ) {
 23+ $script = self::stripComments( $script );
 24+ $script = self::stripHorizontalSpace( $script );
 25+ // If requested, make some vertical whitespace collapsing as well
 26+ if ( $collapseVertical ) {
 27+ $script = self::stripVerticalSpace( $script );
 28+ }
 29+ // Done
 30+ return $script;
 31+ }
 32+
 33+ private static function stripComments( $script ) {
 34+ $parser = self::createParser();
 35+ // Remove comments
 36+ $parser->add( '/\\/\\/[^\\r\\n]*[\\r\\n]/' );
 37+ $parser->add( '/\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\//' );
 38+ // Execute and return
 39+ return $parser->exec( $script );
 40+ }
 41+
 42+ private static function stripHorizontalSpace( $script ) {
 43+ $parser = self::createParser();
 44+ // Collapse horizontal whitespaces between variable names into a single space
 45+ $parser->add( '/(\\b|\\$)[ \\t]+(\\b|\\$)/', '$2 $3' );
 46+ // Collapse horizontal whitespaces between unary operators into a single space
 47+ $parser->add( '/([+\\-])[ \\t]+([+\\-])/', '$2 $3' );
 48+ // Remove all remaining un-protected horizontal whitespace
 49+ $parser->add( '/[ \\t]+/');
 50+ // Collapse multiple vertical whitespaces with some horizontal spaces between them
 51+ $parser->add( '/[\\r\\n]+[ \\t]*[\\r\\n]+/', "\n" );
 52+ // Execute and return
 53+ return $parser->exec($script);
 54+ }
 55+
 56+ private static function stripVerticalSpace( $script ) {
 57+ $parser = self::createParser();
 58+ // Collapse whitespaces between and after a ){ pair (function definitions)
 59+ $parser->add( '/\\)\\s+\\{\\s+/', '){' );
 60+ // Collapse whitespaces between and after a ({ pair (JSON argument)
 61+ $parser->add( '/\\(\\s+\\{\\s+/', '({' );
 62+ // Collapse whitespaces between a parenthesis and a period (call chaining)
 63+ $parser->add( '/\\)\\s+\\./', ').');
 64+ // Collapse vertical whitespaces which come directly after a semicolon or a comma
 65+ $parser->add( '/([;,])\\s+/', '$2' );
 66+ // Collapse whitespaces between multiple parenthesis/brackets of similar direction
 67+ $parser->add( '/([\\)\\}])\\s+([\\)\\}])/', '$2$3' );
 68+ $parser->add( '/([\\(\\{])\\s+([\\(\\{])/', '$2$3' );
 69+ return $parser->exec( $script );
 70+ }
 71+
 72+ /*
 73+ * Creates an instance of ParseMaster and protects sensitive JavaScript regions.
 74+ *
 75+ * This parser is based on regular expressions, which all get or'd together, so rules take
 76+ * precedence in the order they are added. We can use it to minify by armoring certain regions
 77+ * by matching them and replacing them with the full match, leaving the remaining regions around
 78+ * for further matching and replacing. When creating rules please note that because ParseMaster
 79+ * "or"s all of the rules together in a single pattern, encapsulating them in parenthesis, $1
 80+ * represents the whole match for a given rule, and $2 is the first submatch.
 81+ */
 82+ private static function createParser() {
2683 $parser = new ParseMaster();
2784 // There is a bug in ParseMaster that causes a backslash at the end of a line to be changed
2885 // to \s if we use a backslash as the escape character. We work around this by using an
@@ -30,46 +87,225 @@
3188 // Protect strings. The original code had [^\'\\v] here, but that didn't armor multiline
3289 // strings correctly. This also armors multiline strings that don't have backslashes at the
3390 // end of the line (these are invalid), but that's fine because we're just armoring here.
34 - $parser->add('/\'[^\']*\'/', '$1' );
35 - $parser->add('/"[^"]*"/', '$1' );
36 - // Remove comments
37 - $parser->add('/\\/\\/[^\v]*[\v]/', ' ');
38 - $parser->add('/\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\//', ' ');
 91+ $parser->add( '/\'[^\']*\'/', '$1' );
 92+ $parser->add( '/"[^"]*"/', '$1' );
3993 // Protect regular expressions
40 - $parser->add('/\\h+(\\/[^\\/\\v\\*][^\\/\\v]*\\/g?i?)/', '$2'); // IGNORE
41 - $parser->add('/[^\\w\\x24\\/\'"*)\\?:]\\/[^\\/\\v\\*][^\\/\\v]*\\/g?i?/', '$1');
42 - // Remove: ;;; doSomething();
43 - $parser->add('/;;;[^\\v]+[\\v]/');
44 - // Remove redundant semi-colons
45 - $parser->add('/\\(;;\\)/', '$1'); // protect for (;;) loops
46 - $parser->add('/;+\\h*([};])/', '$2');
47 - // Apply all rules defined up to this point
48 - $script = $parser->exec($script);
49 - // If requested, make some vertical whitespace collapsing as well
50 - if ( $collapseVertical ) {
51 - // Collapse whitespaces between and after a ){ pair (function definitions)
52 - $parser->add('/\\)\\s+\\{\\s+/', '){');
53 - // Collapse whitespaces between and after a ({ pair (JSON argument)
54 - $parser->add('/\\(\\s+\\{\\s+/', '({');
55 - // Collapse whitespaces between a parenthesis and a period (call chaining)
56 - $parser->add('/\\)\\s+\\./', ').');
57 - // Collapse vertical whitespaces which come directly after a semicolon or a comma
58 - $parser->add('/([;,])\\s+/', '$2');
59 - // Collapse whitespaces between multiple parenthesis/brackets of similar direction
60 - $parser->add('/([\\)\\}])\\s+([\\)\\}])/', '$2$3');
61 - $parser->add('/([\\(\\{])\\s+([\\(\\{])/', '$2$3');
 94+ $parser->add( '/[ \\t]+(\\/[^\\/\\r\\n\\*][^\\/\\r\\n]*\\/g?i?)/', '$2' );
 95+ $parser->add( '/[^\\w\\$\\/\'"*)\\?:]\\/[^\\/\\r\\n\\*][^\\/\\r\\n]*\\/g?i?/', '$1' );
 96+ return $parser;
 97+ }
 98+}
 99+
 100+/**
 101+ * ParseMaster, version 1.0.2 (2005-08-19) Copyright 2005, Dean Edwards
 102+ * A multi-pattern parser.
 103+ * License: http://creativecommons.org/licenses/LGPL/2.1/
 104+ *
 105+ * This is the PHP version of the ParseMaster component of Dean Edwards' (http://dean.edwards.name/)
 106+ * Packer, which was originally written in JavaScript. It was ported to PHP by Nicolas Martin.
 107+ *
 108+ * Original Source: http://joliclic.free.fr/php/javascript-packer/en/
 109+ *
 110+ * Changes should be pushed back upstream.
 111+ */
 112+class ParseMaster {
 113+ public $ignoreCase = false;
 114+ public $escapeChar = '';
 115+
 116+ // constants
 117+ const EXPRESSION = 0;
 118+ const REPLACEMENT = 1;
 119+ const LENGTH = 2;
 120+
 121+ // used to determine nesting levels
 122+ private $GROUPS = '/\\(/';//g
 123+ private $SUB_REPLACE = '/\\$\\d/';
 124+ private $INDEXED = '/^\\$\\d+$/';
 125+ private $TRIM = '/([\'"])\\1\\.(.*)\\.\\1\\1$/';
 126+ private $ESCAPE = '/\\\./';//g
 127+ private $QUOTE = '/\'/';
 128+ private $DELETED = '/\\x01[^\\x01]*\\x01/';//g
 129+
 130+ public function add($expression, $replacement = '') {
 131+ // count the number of sub-expressions
 132+ // - add one because each pattern is itself a sub-expression
 133+ $length = 1 + preg_match_all($this->GROUPS, $this->_internalEscape((string)$expression), $out);
 134+
 135+ // treat only strings $replacement
 136+ if (is_string($replacement)) {
 137+ // does the pattern deal with sub-expressions?
 138+ if (preg_match($this->SUB_REPLACE, $replacement)) {
 139+ // a simple lookup? (e.g. "$2")
 140+ if (preg_match($this->INDEXED, $replacement)) {
 141+ // store the index (used for fast retrieval of matched strings)
 142+ $replacement = (int)(substr($replacement, 1)) - 1;
 143+ } else { // a complicated lookup (e.g. "Hello $2 $1")
 144+ // build a function to do the lookup
 145+ $quote = preg_match($this->QUOTE, $this->_internalEscape($replacement))
 146+ ? '"' : "'";
 147+ $replacement = array(
 148+ 'fn' => '_backReferences',
 149+ 'data' => array(
 150+ 'replacement' => $replacement,
 151+ 'length' => $length,
 152+ 'quote' => $quote
 153+ )
 154+ );
 155+ }
 156+ }
62157 }
63 - // Collapse horizontal whitespaces between variable names into a single space
64 - $parser->add('/(\\b|\\x24)\\h+(\\b|\\x24)/', '$2 $3');
65 - // Collapse horizontal whitespaces between urinary operators into a single space
66 - $parser->add('/([+\\-])\\h+([+\\-])/', '$2 $3');
67 - // Collapse all remaining un-protected horizontal whitespace
68 - $parser->add('/\\h+/', '');
69 - // Collapse multiple vertical whitespaces with some horizontal spaces between them
70 - $parser->add('/\\v+\\h*\\v*/', "\n");
 158+ // pass the modified arguments
 159+ if (!empty($expression)) $this->_add($expression, $replacement, $length);
 160+ else $this->_add('/^$/', $replacement, $length);
 161+ }
 162+
 163+ public function exec($string) {
 164+ // execute the global replacement
 165+ $this->_escaped = array();
71166
72 - // Done
73 - return $parser->exec($script);
 167+ // simulate the _patterns.toSTring of Dean
 168+ $regexp = '/';
 169+ foreach ($this->_patterns as $reg) {
 170+ $regexp .= '(' . substr($reg[self::EXPRESSION], 1, -1) . ')|';
 171+ }
 172+ $regexp = substr($regexp, 0, -1) . '/';
 173+ $regexp .= ($this->ignoreCase) ? 'i' : '';
74174
 175+ $string = $this->_escape($string, $this->escapeChar);
 176+ $string = preg_replace_callback(
 177+ $regexp,
 178+ array(
 179+ &$this,
 180+ '_replacement'
 181+ ),
 182+ $string
 183+ );
 184+ $string = $this->_unescape($string, $this->escapeChar);
 185+
 186+ return preg_replace($this->DELETED, '', $string);
75187 }
 188+
 189+ public function reset() {
 190+ // clear the patterns collection so that this object may be re-used
 191+ $this->_patterns = array();
 192+ }
 193+
 194+ // private
 195+ private $_escaped = array(); // escaped characters
 196+ private $_patterns = array(); // patterns stored by index
 197+
 198+ // create and add a new pattern to the patterns collection
 199+ private function _add() {
 200+ $arguments = func_get_args();
 201+ $this->_patterns[] = $arguments;
 202+ }
 203+
 204+ // this is the global replace function (it's quite complicated)
 205+ private function _replacement($arguments) {
 206+ if (empty($arguments)) return '';
 207+
 208+ $i = 1; $j = 0;
 209+ // loop through the patterns
 210+ while (isset($this->_patterns[$j])) {
 211+ $pattern = $this->_patterns[$j++];
 212+ // do we have a result?
 213+ if (isset($arguments[$i]) && ($arguments[$i] != '')) {
 214+ $replacement = $pattern[self::REPLACEMENT];
 215+
 216+ if (is_array($replacement) && isset($replacement['fn'])) {
 217+
 218+ if (isset($replacement['data'])) $this->buffer = $replacement['data'];
 219+ return call_user_func(array(&$this, $replacement['fn']), $arguments, $i);
 220+
 221+ } elseif (is_int($replacement)) {
 222+ return $arguments[$replacement + $i];
 223+
 224+ }
 225+ $delete = ($this->escapeChar == '' ||
 226+ strpos($arguments[$i], $this->escapeChar) === false)
 227+ ? '' : "\x01" . $arguments[$i] . "\x01";
 228+ return $delete . $replacement;
 229+
 230+ // skip over references to sub-expressions
 231+ } else {
 232+ $i += $pattern[self::LENGTH];
 233+ }
 234+ }
 235+ }
 236+
 237+ private function _backReferences($match, $offset) {
 238+ $replacement = $this->buffer['replacement'];
 239+ $quote = $this->buffer['quote'];
 240+ $i = $this->buffer['length'];
 241+ while ($i) {
 242+ $replacement = str_replace('$'.$i--, $match[$offset + $i], $replacement);
 243+ }
 244+ return $replacement;
 245+ }
 246+
 247+ private function _replace_name($match, $offset){
 248+ $length = strlen($match[$offset + 2]);
 249+ $start = $length - max($length - strlen($match[$offset + 3]), 0);
 250+ return substr($match[$offset + 1], $start, $length) . $match[$offset + 4];
 251+ }
 252+
 253+ private function _replace_encoded($match, $offset) {
 254+ return $this->buffer[$match[$offset]];
 255+ }
 256+
 257+
 258+ // php : we cannot pass additional data to preg_replace_callback,
 259+ // and we cannot use &$this in create_function, so let's go to lower level
 260+ private $buffer;
 261+
 262+ // encode escaped characters
 263+ private function _escape($string, $escapeChar) {
 264+ if ($escapeChar) {
 265+ $this->buffer = $escapeChar;
 266+ return preg_replace_callback(
 267+ '/\\' . $escapeChar . '(.)' .'/',
 268+ array(&$this, '_escapeBis'),
 269+ $string
 270+ );
 271+
 272+ } else {
 273+ return $string;
 274+ }
 275+ }
 276+ private function _escapeBis($match) {
 277+ $this->_escaped[] = $match[1];
 278+ return $this->buffer;
 279+ }
 280+
 281+ // decode escaped characters
 282+ private function _unescape($string, $escapeChar) {
 283+ if ($escapeChar) {
 284+ $regexp = '/'.'\\'.$escapeChar.'/';
 285+ $this->buffer = array('escapeChar'=> $escapeChar, 'i' => 0);
 286+ return preg_replace_callback
 287+ (
 288+ $regexp,
 289+ array(&$this, '_unescapeBis'),
 290+ $string
 291+ );
 292+
 293+ } else {
 294+ return $string;
 295+ }
 296+ }
 297+ private function _unescapeBis() {
 298+ if (isset($this->_escaped[$this->buffer['i']])
 299+ && $this->_escaped[$this->buffer['i']] != '')
 300+ {
 301+ $temp = $this->_escaped[$this->buffer['i']];
 302+ } else {
 303+ $temp = '';
 304+ }
 305+ $this->buffer['i']++;
 306+ return $this->buffer['escapeChar'] . $temp;
 307+ }
 308+
 309+ private function _internalEscape($string) {
 310+ return preg_replace($this->ESCAPE, '', $string);
 311+ }
76312 }
Index: trunk/phase3/includes/DefaultSettings.php
@@ -2448,6 +2448,10 @@
24492449 */
24502450 $wgResourceLoaderUseESI = false;
24512451
 2452+/**
 2453+ * Enable removal of some of the vertical whitespace (like \r and \n) from
 2454+ * JavaScript code when minifying.
 2455+ */
24522456 $wgResourceLoaderMinifyJSVerticalSpace = false;
24532457
24542458 /** @} */ # End of resource loader settings }
Index: trunk/phase3/includes/AutoLoader.php
@@ -180,7 +180,6 @@
181181 'PageHistory' => 'includes/HistoryPage.php',
182182 'PageHistoryPager' => 'includes/HistoryPage.php',
183183 'Pager' => 'includes/Pager.php',
184 - 'ParseMaster' => 'includes/libs/ParseMaster.php',
185184 'PasswordError' => 'includes/User.php',
186185 'PatrolLog' => 'includes/PatrolLog.php',
187186 'PhpHttpRequest' => 'includes/HttpFunctions.php',

Follow-up revisions

RevisionCommit summaryAuthorDate
r806771.17: MFT r80109, r80113, r80223, r80475, r80554, r80575, r80620, r80621, r80...catrope03:12, 21 January 2011
r80692Fix r80666: botched variable renamecatrope17:23, 21 January 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r80656Resolved bug 26791 by replacing JSMin with a new library called JavaScriptDis...tparscal21:57, 20 January 2011

Status & tagging log