[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/parser/ -> ParserOptions.php (source)

   1  <?php
   2  /**
   3   * Options for the PHP parser
   4   *
   5   * This program is free software; you can redistribute it and/or modify
   6   * it under the terms of the GNU General Public License as published by
   7   * the Free Software Foundation; either version 2 of the License, or
   8   * (at your option) any later version.
   9   *
  10   * This program is distributed in the hope that it will be useful,
  11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13   * GNU General Public License for more details.
  14   *
  15   * You should have received a copy of the GNU General Public License along
  16   * with this program; if not, write to the Free Software Foundation, Inc.,
  17   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18   * http://www.gnu.org/copyleft/gpl.html
  19   *
  20   * @file
  21   * @ingroup Parser
  22   */
  23  
  24  /**
  25   * @brief Set options of the Parser
  26   *
  27   * All member variables are supposed to be private in theory, although in
  28   * practise this is not the case.
  29   *
  30   * @ingroup Parser
  31   */
  32  class ParserOptions {
  33  
  34      /**
  35       * Interlanguage links are removed and returned in an array
  36       */
  37      public $mInterwikiMagic;
  38  
  39      /**
  40       * Allow external images inline?
  41       */
  42      public $mAllowExternalImages;
  43  
  44      /**
  45       * If not, any exception?
  46       */
  47      public $mAllowExternalImagesFrom;
  48  
  49      /**
  50       * If not or it doesn't match, should we check an on-wiki whitelist?
  51       */
  52      public $mEnableImageWhitelist;
  53  
  54      /**
  55       * Date format index
  56       */
  57      public $mDateFormat = null;
  58  
  59      /**
  60       * Create "edit section" links?
  61       */
  62      public $mEditSection = true;
  63  
  64      /**
  65       * Allow inclusion of special pages?
  66       */
  67      public $mAllowSpecialInclusion;
  68  
  69      /**
  70       * Use tidy to cleanup output HTML?
  71       */
  72      public $mTidy = false;
  73  
  74      /**
  75       * Which lang to call for PLURAL and GRAMMAR
  76       */
  77      public $mInterfaceMessage = false;
  78  
  79      /**
  80       * Overrides $mInterfaceMessage with arbitrary language
  81       */
  82      public $mTargetLanguage = null;
  83  
  84      /**
  85       * Maximum size of template expansions, in bytes
  86       */
  87      public $mMaxIncludeSize;
  88  
  89      /**
  90       * Maximum number of nodes touched by PPFrame::expand()
  91       */
  92      public $mMaxPPNodeCount;
  93  
  94      /**
  95       * Maximum number of nodes generated by Preprocessor::preprocessToObj()
  96       */
  97      public $mMaxGeneratedPPNodeCount;
  98  
  99      /**
 100       * Maximum recursion depth in PPFrame::expand()
 101       */
 102      public $mMaxPPExpandDepth;
 103  
 104      /**
 105       * Maximum recursion depth for templates within templates
 106       */
 107      public $mMaxTemplateDepth;
 108  
 109      /**
 110       * Maximum number of calls per parse to expensive parser functions
 111       */
 112      public $mExpensiveParserFunctionLimit;
 113  
 114      /**
 115       * Remove HTML comments. ONLY APPLIES TO PREPROCESS OPERATIONS
 116       */
 117      public $mRemoveComments = true;
 118  
 119      /**
 120       * Callback for template fetching. Used as first argument to call_user_func().
 121       */
 122      public $mTemplateCallback =
 123          array( 'Parser', 'statelessFetchTemplate' );
 124  
 125      /**
 126       * Enable limit report in an HTML comment on output
 127       */
 128      public $mEnableLimitReport = false;
 129  
 130      /**
 131       * Timestamp used for {{CURRENTDAY}} etc.
 132       */
 133      public $mTimestamp;
 134  
 135      /**
 136       * Target attribute for external links
 137       */
 138      public $mExternalLinkTarget;
 139  
 140      /**
 141       * Clean up signature texts?
 142       *
 143       * 1) Strip ~~~, ~~~~ and ~~~~~ out of signatures
 144       * 2) Substitute all transclusions
 145       */
 146      public $mCleanSignatures;
 147  
 148      /**
 149       * Transform wiki markup when saving the page?
 150       */
 151      public $mPreSaveTransform = true;
 152  
 153      /**
 154       * Whether content conversion should be disabled
 155       */
 156      public $mDisableContentConversion;
 157  
 158      /**
 159       * Whether title conversion should be disabled
 160       */
 161      public $mDisableTitleConversion;
 162  
 163      /**
 164       * Automatically number headings?
 165       */
 166      public $mNumberHeadings;
 167  
 168      /**
 169       * Thumb size preferred by the user.
 170       */
 171      public $mThumbSize;
 172  
 173      /**
 174       * Maximum article size of an article to be marked as "stub"
 175       */
 176      private $mStubThreshold;
 177  
 178      /**
 179       * Language object of the User language.
 180       */
 181      public $mUserLang;
 182  
 183      /**
 184       * @var User
 185       * Stored user object
 186       */
 187      public $mUser;
 188  
 189      /**
 190       * Parsing the page for a "preview" operation?
 191       */
 192      public $mIsPreview = false;
 193  
 194      /**
 195       * Parsing the page for a "preview" operation on a single section?
 196       */
 197      public $mIsSectionPreview = false;
 198  
 199      /**
 200       * Parsing the printable version of the page?
 201       */
 202      public $mIsPrintable = false;
 203  
 204      /**
 205       * Extra key that should be present in the caching key.
 206       */
 207      public $mExtraKey = '';
 208  
 209      /**
 210       * Function to be called when an option is accessed.
 211       */
 212      protected $onAccessCallback = null;
 213  
 214      /**
 215       * If the page being parsed is a redirect, this should hold the redirect
 216       * target.
 217       * @var Title|null
 218       */
 219      private $redirectTarget = null;
 220  
 221  	public function getInterwikiMagic() {
 222          return $this->mInterwikiMagic;
 223      }
 224  
 225  	public function getAllowExternalImages() {
 226          return $this->mAllowExternalImages;
 227      }
 228  
 229  	public function getAllowExternalImagesFrom() {
 230          return $this->mAllowExternalImagesFrom;
 231      }
 232  
 233  	public function getEnableImageWhitelist() {
 234          return $this->mEnableImageWhitelist;
 235      }
 236  
 237  	public function getEditSection() {
 238          return $this->mEditSection;
 239      }
 240  
 241  	public function getNumberHeadings() {
 242          $this->optionUsed( 'numberheadings' );
 243  
 244          return $this->mNumberHeadings;
 245      }
 246  
 247  	public function getAllowSpecialInclusion() {
 248          return $this->mAllowSpecialInclusion;
 249      }
 250  
 251  	public function getTidy() {
 252          return $this->mTidy;
 253      }
 254  
 255  	public function getInterfaceMessage() {
 256          return $this->mInterfaceMessage;
 257      }
 258  
 259  	public function getTargetLanguage() {
 260          return $this->mTargetLanguage;
 261      }
 262  
 263  	public function getMaxIncludeSize() {
 264          return $this->mMaxIncludeSize;
 265      }
 266  
 267  	public function getMaxPPNodeCount() {
 268          return $this->mMaxPPNodeCount;
 269      }
 270  
 271  	public function getMaxGeneratedPPNodeCount() {
 272          return $this->mMaxGeneratedPPNodeCount;
 273      }
 274  
 275  	public function getMaxPPExpandDepth() {
 276          return $this->mMaxPPExpandDepth;
 277      }
 278  
 279  	public function getMaxTemplateDepth() {
 280          return $this->mMaxTemplateDepth;
 281      }
 282  
 283      /* @since 1.20 */
 284  	public function getExpensiveParserFunctionLimit() {
 285          return $this->mExpensiveParserFunctionLimit;
 286      }
 287  
 288  	public function getRemoveComments() {
 289          return $this->mRemoveComments;
 290      }
 291  
 292  	public function getTemplateCallback() {
 293          return $this->mTemplateCallback;
 294      }
 295  
 296  	public function getEnableLimitReport() {
 297          return $this->mEnableLimitReport;
 298      }
 299  
 300  	public function getCleanSignatures() {
 301          return $this->mCleanSignatures;
 302      }
 303  
 304  	public function getExternalLinkTarget() {
 305          return $this->mExternalLinkTarget;
 306      }
 307  
 308  	public function getDisableContentConversion() {
 309          return $this->mDisableContentConversion;
 310      }
 311  
 312  	public function getDisableTitleConversion() {
 313          return $this->mDisableTitleConversion;
 314      }
 315  
 316  	public function getThumbSize() {
 317          $this->optionUsed( 'thumbsize' );
 318  
 319          return $this->mThumbSize;
 320      }
 321  
 322  	public function getStubThreshold() {
 323          $this->optionUsed( 'stubthreshold' );
 324  
 325          return $this->mStubThreshold;
 326      }
 327  
 328  	public function getIsPreview() {
 329          return $this->mIsPreview;
 330      }
 331  
 332  	public function getIsSectionPreview() {
 333          return $this->mIsSectionPreview;
 334      }
 335  
 336  	public function getIsPrintable() {
 337          $this->optionUsed( 'printable' );
 338  
 339          return $this->mIsPrintable;
 340      }
 341  
 342  	public function getUser() {
 343          return $this->mUser;
 344      }
 345  
 346  	public function getPreSaveTransform() {
 347          return $this->mPreSaveTransform;
 348      }
 349  
 350  	public function getDateFormat() {
 351          $this->optionUsed( 'dateformat' );
 352          if ( !isset( $this->mDateFormat ) ) {
 353              $this->mDateFormat = $this->mUser->getDatePreference();
 354          }
 355          return $this->mDateFormat;
 356      }
 357  
 358  	public function getTimestamp() {
 359          if ( !isset( $this->mTimestamp ) ) {
 360              $this->mTimestamp = wfTimestampNow();
 361          }
 362          return $this->mTimestamp;
 363      }
 364  
 365      /**
 366       * Get the user language used by the parser for this page.
 367       *
 368       * You shouldn't use this. Really. $parser->getFunctionLang() is all you need.
 369       *
 370       * To avoid side-effects where the page will be rendered based on the language
 371       * of the user who last saved, this function will triger a cache fragmentation.
 372       * Usage of this method is discouraged for that reason.
 373       *
 374       * When saving, this will return the default language instead of the user's.
 375       *
 376       * {{int: }} uses this which used to produce inconsistent link tables (bug 14404).
 377       *
 378       * @return Language
 379       * @since 1.19
 380       */
 381  	public function getUserLangObj() {
 382          $this->optionUsed( 'userlang' );
 383          return $this->mUserLang;
 384      }
 385  
 386      /**
 387       * Same as getUserLangObj() but returns a string instead.
 388       *
 389       * @return string Language code
 390       * @since 1.17
 391       */
 392  	public function getUserLang() {
 393          return $this->getUserLangObj()->getCode();
 394      }
 395  
 396  	public function setInterwikiMagic( $x ) {
 397          return wfSetVar( $this->mInterwikiMagic, $x );
 398      }
 399  
 400  	public function setAllowExternalImages( $x ) {
 401          return wfSetVar( $this->mAllowExternalImages, $x );
 402      }
 403  
 404  	public function setAllowExternalImagesFrom( $x ) {
 405          return wfSetVar( $this->mAllowExternalImagesFrom, $x );
 406      }
 407  
 408  	public function setEnableImageWhitelist( $x ) {
 409          return wfSetVar( $this->mEnableImageWhitelist, $x );
 410      }
 411  
 412  	public function setDateFormat( $x ) {
 413          return wfSetVar( $this->mDateFormat, $x );
 414      }
 415  
 416  	public function setEditSection( $x ) {
 417          return wfSetVar( $this->mEditSection, $x );
 418      }
 419  
 420  	public function setNumberHeadings( $x ) {
 421          return wfSetVar( $this->mNumberHeadings, $x );
 422      }
 423  
 424  	public function setAllowSpecialInclusion( $x ) {
 425          return wfSetVar( $this->mAllowSpecialInclusion, $x );
 426      }
 427  
 428  	public function setTidy( $x ) {
 429          return wfSetVar( $this->mTidy, $x );
 430      }
 431  
 432  	public function setInterfaceMessage( $x ) {
 433          return wfSetVar( $this->mInterfaceMessage, $x );
 434      }
 435  
 436  	public function setTargetLanguage( $x ) {
 437          return wfSetVar( $this->mTargetLanguage, $x, true );
 438      }
 439  
 440  	public function setMaxIncludeSize( $x ) {
 441          return wfSetVar( $this->mMaxIncludeSize, $x );
 442      }
 443  
 444  	public function setMaxPPNodeCount( $x ) {
 445          return wfSetVar( $this->mMaxPPNodeCount, $x );
 446      }
 447  
 448  	public function setMaxGeneratedPPNodeCount( $x ) {
 449          return wfSetVar( $this->mMaxGeneratedPPNodeCount, $x );
 450      }
 451  
 452  	public function setMaxTemplateDepth( $x ) {
 453          return wfSetVar( $this->mMaxTemplateDepth, $x );
 454      }
 455  
 456      /* @since 1.20 */
 457  	public function setExpensiveParserFunctionLimit( $x ) {
 458          return wfSetVar( $this->mExpensiveParserFunctionLimit, $x );
 459      }
 460  
 461  	public function setRemoveComments( $x ) {
 462          return wfSetVar( $this->mRemoveComments, $x );
 463      }
 464  
 465  	public function setTemplateCallback( $x ) {
 466          return wfSetVar( $this->mTemplateCallback, $x );
 467      }
 468  
 469  	public function enableLimitReport( $x = true ) {
 470          return wfSetVar( $this->mEnableLimitReport, $x );
 471      }
 472  
 473  	public function setTimestamp( $x ) {
 474          return wfSetVar( $this->mTimestamp, $x );
 475      }
 476  
 477  	public function setCleanSignatures( $x ) {
 478          return wfSetVar( $this->mCleanSignatures, $x );
 479      }
 480  
 481  	public function setExternalLinkTarget( $x ) {
 482          return wfSetVar( $this->mExternalLinkTarget, $x );
 483      }
 484  
 485  	public function disableContentConversion( $x = true ) {
 486          return wfSetVar( $this->mDisableContentConversion, $x );
 487      }
 488  
 489  	public function disableTitleConversion( $x = true ) {
 490          return wfSetVar( $this->mDisableTitleConversion, $x );
 491      }
 492  
 493  	public function setUserLang( $x ) {
 494          if ( is_string( $x ) ) {
 495              $x = Language::factory( $x );
 496          }
 497  
 498          return wfSetVar( $this->mUserLang, $x );
 499      }
 500  
 501  	public function setThumbSize( $x ) {
 502          return wfSetVar( $this->mThumbSize, $x );
 503      }
 504  
 505  	public function setStubThreshold( $x ) {
 506          return wfSetVar( $this->mStubThreshold, $x );
 507      }
 508  
 509  	public function setPreSaveTransform( $x ) {
 510          return wfSetVar( $this->mPreSaveTransform, $x );
 511      }
 512  
 513  	public function setIsPreview( $x ) {
 514          return wfSetVar( $this->mIsPreview, $x );
 515      }
 516  
 517  	public function setIsSectionPreview( $x ) {
 518          return wfSetVar( $this->mIsSectionPreview, $x );
 519      }
 520  
 521  	public function setIsPrintable( $x ) {
 522          return wfSetVar( $this->mIsPrintable, $x );
 523      }
 524  
 525      /**
 526       * Set the redirect target.
 527       *
 528       * Note that setting or changing this does not *make* the page a redirect
 529       * or change its target, it merely records the information for reference
 530       * during the parse.
 531       *
 532       * @since 1.24
 533       * @param Title|null $title
 534       */
 535  	function setRedirectTarget( $title ) {
 536          $this->redirectTarget = $title;
 537      }
 538  
 539      /**
 540       * Get the previously-set redirect target.
 541       *
 542       * @since 1.24
 543       * @return Title|null
 544       */
 545  	function getRedirectTarget() {
 546          return $this->redirectTarget;
 547      }
 548  
 549      /**
 550       * Extra key that should be present in the parser cache key.
 551       * @param string $key
 552       */
 553  	public function addExtraKey( $key ) {
 554          $this->mExtraKey .= '!' . $key;
 555      }
 556  
 557      /**
 558       * Constructor
 559       * @param User $user
 560       * @param Language $lang
 561       */
 562  	public function __construct( $user = null, $lang = null ) {
 563          if ( $user === null ) {
 564              global $wgUser;
 565              if ( $wgUser === null ) {
 566                  $user = new User;
 567              } else {
 568                  $user = $wgUser;
 569              }
 570          }
 571          if ( $lang === null ) {
 572              global $wgLang;
 573              if ( !StubObject::isRealObject( $wgLang ) ) {
 574                  $wgLang->_unstub();
 575              }
 576              $lang = $wgLang;
 577          }
 578          $this->initialiseFromUser( $user, $lang );
 579      }
 580  
 581      /**
 582       * Get a ParserOptions object from a given user.
 583       * Language will be taken from $wgLang.
 584       *
 585       * @param User $user
 586       * @return ParserOptions
 587       */
 588  	public static function newFromUser( $user ) {
 589          return new ParserOptions( $user );
 590      }
 591  
 592      /**
 593       * Get a ParserOptions object from a given user and language
 594       *
 595       * @param User $user
 596       * @param Language $lang
 597       * @return ParserOptions
 598       */
 599  	public static function newFromUserAndLang( User $user, Language $lang ) {
 600          return new ParserOptions( $user, $lang );
 601      }
 602  
 603      /**
 604       * Get a ParserOptions object from a IContextSource object
 605       *
 606       * @param IContextSource $context
 607       * @return ParserOptions
 608       */
 609  	public static function newFromContext( IContextSource $context ) {
 610          return new ParserOptions( $context->getUser(), $context->getLanguage() );
 611      }
 612  
 613      /**
 614       * Get user options
 615       *
 616       * @param User $user
 617       * @param Language $lang
 618       */
 619  	private function initialiseFromUser( $user, $lang ) {
 620          global $wgInterwikiMagic, $wgAllowExternalImages,
 621              $wgAllowExternalImagesFrom, $wgEnableImageWhitelist, $wgAllowSpecialInclusion,
 622              $wgMaxArticleSize, $wgMaxPPNodeCount, $wgMaxTemplateDepth, $wgMaxPPExpandDepth,
 623              $wgCleanSignatures, $wgExternalLinkTarget, $wgExpensiveParserFunctionLimit,
 624              $wgMaxGeneratedPPNodeCount, $wgDisableLangConversion, $wgDisableTitleConversion;
 625  
 626          wfProfileIn( __METHOD__ );
 627  
 628          $this->mInterwikiMagic = $wgInterwikiMagic;
 629          $this->mAllowExternalImages = $wgAllowExternalImages;
 630          $this->mAllowExternalImagesFrom = $wgAllowExternalImagesFrom;
 631          $this->mEnableImageWhitelist = $wgEnableImageWhitelist;
 632          $this->mAllowSpecialInclusion = $wgAllowSpecialInclusion;
 633          $this->mMaxIncludeSize = $wgMaxArticleSize * 1024;
 634          $this->mMaxPPNodeCount = $wgMaxPPNodeCount;
 635          $this->mMaxGeneratedPPNodeCount = $wgMaxGeneratedPPNodeCount;
 636          $this->mMaxPPExpandDepth = $wgMaxPPExpandDepth;
 637          $this->mMaxTemplateDepth = $wgMaxTemplateDepth;
 638          $this->mExpensiveParserFunctionLimit = $wgExpensiveParserFunctionLimit;
 639          $this->mCleanSignatures = $wgCleanSignatures;
 640          $this->mExternalLinkTarget = $wgExternalLinkTarget;
 641          $this->mDisableContentConversion = $wgDisableLangConversion;
 642          $this->mDisableTitleConversion = $wgDisableLangConversion || $wgDisableTitleConversion;
 643  
 644          $this->mUser = $user;
 645          $this->mNumberHeadings = $user->getOption( 'numberheadings' );
 646          $this->mThumbSize = $user->getOption( 'thumbsize' );
 647          $this->mStubThreshold = $user->getStubThreshold();
 648          $this->mUserLang = $lang;
 649  
 650          wfProfileOut( __METHOD__ );
 651      }
 652  
 653      /**
 654       * Registers a callback for tracking which ParserOptions which are used.
 655       * This is a private API with the parser.
 656       * @param callable $callback
 657       */
 658  	public function registerWatcher( $callback ) {
 659          $this->onAccessCallback = $callback;
 660      }
 661  
 662      /**
 663       * Called when an option is accessed.
 664       * @param string $optionName Name of the option
 665       */
 666  	public function optionUsed( $optionName ) {
 667          if ( $this->onAccessCallback ) {
 668              call_user_func( $this->onAccessCallback, $optionName );
 669          }
 670      }
 671  
 672      /**
 673       * Returns the full array of options that would have been used by
 674       * in 1.16.
 675       * Used to get the old parser cache entries when available.
 676       * @return array
 677       */
 678  	public static function legacyOptions() {
 679          return array(
 680              'stubthreshold',
 681              'numberheadings',
 682              'userlang',
 683              'thumbsize',
 684              'editsection',
 685              'printable'
 686          );
 687      }
 688  
 689      /**
 690       * Generate a hash string with the values set on these ParserOptions
 691       * for the keys given in the array.
 692       * This will be used as part of the hash key for the parser cache,
 693       * so users sharing the options with vary for the same page share
 694       * the same cached data safely.
 695       *
 696       * Extensions which require it should install 'PageRenderingHash' hook,
 697       * which will give them a chance to modify this key based on their own
 698       * settings.
 699       *
 700       * @since 1.17
 701       * @param array $forOptions
 702       * @param Title $title Used to get the content language of the page (since r97636)
 703       * @return string Page rendering hash
 704       */
 705  	public function optionsHash( $forOptions, $title = null ) {
 706          global $wgRenderHashAppend;
 707  
 708          // FIXME: Once the cache key is reorganized this argument
 709          // can be dropped. It was used when the math extension was
 710          // part of core.
 711          $confstr = '*';
 712  
 713          // Space assigned for the stubthreshold but unused
 714          // since it disables the parser cache, its value will always
 715          // be 0 when this function is called by parsercache.
 716          if ( in_array( 'stubthreshold', $forOptions ) ) {
 717              $confstr .= '!' . $this->mStubThreshold;
 718          } else {
 719              $confstr .= '!*';
 720          }
 721  
 722          if ( in_array( 'dateformat', $forOptions ) ) {
 723              $confstr .= '!' . $this->getDateFormat();
 724          }
 725  
 726          if ( in_array( 'numberheadings', $forOptions ) ) {
 727              $confstr .= '!' . ( $this->mNumberHeadings ? '1' : '' );
 728          } else {
 729              $confstr .= '!*';
 730          }
 731  
 732          if ( in_array( 'userlang', $forOptions ) ) {
 733              $confstr .= '!' . $this->mUserLang->getCode();
 734          } else {
 735              $confstr .= '!*';
 736          }
 737  
 738          if ( in_array( 'thumbsize', $forOptions ) ) {
 739              $confstr .= '!' . $this->mThumbSize;
 740          } else {
 741              $confstr .= '!*';
 742          }
 743  
 744          // add in language specific options, if any
 745          // @todo FIXME: This is just a way of retrieving the url/user preferred variant
 746          if ( !is_null( $title ) ) {
 747              $confstr .= $title->getPageLanguage()->getExtraHashOptions();
 748          } else {
 749              global $wgContLang;
 750              $confstr .= $wgContLang->getExtraHashOptions();
 751          }
 752  
 753          $confstr .= $wgRenderHashAppend;
 754  
 755          if ( !in_array( 'editsection', $forOptions ) ) {
 756              $confstr .= '!*';
 757          } elseif ( !$this->mEditSection ) {
 758              $confstr .= '!edit=0';
 759          }
 760  
 761          if ( $this->mIsPrintable && in_array( 'printable', $forOptions ) ) {
 762              $confstr .= '!printable=1';
 763          }
 764  
 765          if ( $this->mExtraKey != '' ) {
 766              $confstr .= $this->mExtraKey;
 767          }
 768  
 769          // Give a chance for extensions to modify the hash, if they have
 770          // extra options or other effects on the parser cache.
 771          wfRunHooks( 'PageRenderingHash', array( &$confstr, $this->getUser(), &$forOptions ) );
 772  
 773          // Make it a valid memcached key fragment
 774          $confstr = str_replace( ' ', '_', $confstr );
 775  
 776          return $confstr;
 777      }
 778  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1