* church of emacs
* Daniel Friesen
* Daniel Kinzler
+* Daniel Renfro
* Danny B.
* David McCabe
* Derk-Jan Hartman
Previously in the "SimpleAntiSpam" extension by Ryan Schmidt.
* populateRevisionLength.php maintenance script updated to also populate
archive.ar_len field.
+* (bug 43571) DatabaseMySQLBase learned to list views, optionally filtered by a
+ prefix. Also fixed PHPUnit test suite when using a MySQL backend containing
+ views.
=== Bug fixes in 1.22 ===
* (bug 47271) $wgContentHandlerUseDB should be set to false during the upgrade
enabled with care.
* (bug 6092) Add expensive parser functions {{REVISIONID:}}, {{REVISIONUSER:}}
and {{REVISIONTIMESTAMP:}} (with friends).
+* Add "wgRelevantUserName" to mw.config containing the current
+ Skin::getRelevantUser value
=== Bug fixes in 1.23 ===
* (bug 41759) The "updated since last visit" markers (on history pages, recent
changes and watchlist) and the talk page message indicator are now correctly
updated when the user is viewing old revisions of pages, instead of always
acting as if the latest revision was being viewed.
+* (bug 56443) Special:ConfirmEmail no longer shows a "Mail a confirmation code"
+ when the email address is already confirmed. Also, consistently use
+ "confirmed", rather than "authenticated", when messaging whether or not the
+ user has confirmed an email address.
=== API changes in 1.23 ===
* (bug 54884) action=parse&prop=categories now indicates hidden and missing
return implode( DIRECTORY_SEPARATOR, $pieces );
}
-/**
- * Do any deferred updates and clear the list
- *
- * @deprecated since 1.19
- * @see DeferredUpdates::doUpdate()
- * @param $commit string
- */
-function wfDoUpdates( $commit = '' ) {
- wfDeprecated( __METHOD__, '1.19' );
- DeferredUpdates::doUpdates( $commit );
-}
-
/**
* Convert an arbitrarily-long digit string from one numeric base
* to another, optionally zero-padding to a minimum column width.
return str_pad( $result, $pad, '0', STR_PAD_LEFT );
}
-/**
- * Create an object with a given name and an array of construct parameters
- *
- * @param $name String
- * @param array $p parameters
- * @return object
- * @deprecated since 1.18, warnings in 1.18, removal in 1.20
- */
-function wfCreateObject( $name, $p ) {
- wfDeprecated( __FUNCTION__, '1.18' );
- return MWFunction::newObj( $name, $p );
-}
-
/**
* @return bool
*/
}
}
-/**
- * Used to be used for outputting text in the installer/updater
- * @deprecated since 1.18, warnings in 1.18, remove in 1.20
- */
-function wfOut( $s ) {
- wfDeprecated( __FUNCTION__, '1.18' );
- global $wgCommandLineMode;
- if ( $wgCommandLineMode ) {
- echo $s;
- } else {
- echo htmlspecialchars( $s );
- }
- flush();
-}
-
/**
* Count down from $n to zero on the terminal, with a one-second pause
* between showing each number. For use in command-line scripts.
$linktext = wfMessage( 'show-big-image' )->escaped();
if ( $this->displayImg->getRepo()->canTransformVia404() ) {
$thumbSizes = $wgImageLimits;
+ // Also include the full sized resolution in the list, so
+ // that users know they can get it. This will link to the
+ // original file asset if mustRender() === false. In the case
+ // that we mustRender, some users have indicated that they would
+ // find it useful to have the full size image in the rendered
+ // image format.
+ $thumbSizes[] = array( $width_orig, $height_orig );
} else {
# Creating thumb links triggers thumbnail generation.
# Just generate the thumb for the current users prefs.
$thumbSizes = array( $this->getImageLimitsFromOption( $user, 'thumbsize' ) );
+ if ( !$this->displayImg->mustRender() ) {
+ // We can safely include a link to the "full-size" preview,
+ // without actually rendering.
+ $thumbSizes[] = array( $width_orig, $height_orig );
+ }
}
# Generate thumbnails or thumbnail links as needed...
$otherSizes = array();
foreach ( $thumbSizes as $size ) {
- if ( $size[0] < $width_orig && $size[1] < $height_orig
+ // We include a thumbnail size in the list, if it is
+ // less than or equal to the original size of the image
+ // asset ($width_orig/$height_orig). We also exclude
+ // the current thumbnail's size ($width/$height)
+ // since that is added to the message separately, so
+ // it can be denoted as the current size being shown.
+ if ( $size[0] <= $width_orig && $size[1] <= $height_orig
&& $size[0] != $width && $size[1] != $height )
{
$sizeLink = $this->makeSizeLink( $params, $size[0], $size[1] );
}
}
}
+ $otherSizes = array_unique( $otherSizes );
$msgsmall = '';
$sizeLinkBigImagePreview = $this->makeSizeLink( $params, $width, $height );
if ( $sizeLinkBigImagePreview ) {
$ns = $title->getNamespace();
$canonicalNamespace = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $title->getNsText();
+ $sk = $this->getSkin();
// Get the relevant title so that AJAX features can use the correct page name
// when making API requests from certain special pages (bug 34972).
- $relevantTitle = $this->getSkin()->getRelevantTitle();
+ $relevantTitle = $sk->getRelevantTitle();
+ $relevantUser = $sk->getRelevantUser();
if ( $ns == NS_SPECIAL ) {
list( $canonicalSpecialPageName, /*...*/ ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
if ( $this->mRedirectedFrom ) {
$vars['wgRedirectedFrom'] = $this->mRedirectedFrom->getPrefixedDBkey();
}
+ if ( $relevantUser ) {
+ $vars['wgRelevantUserName'] = $relevantUser->getName();
+ }
// Allow extensions to add their custom variables to the mw.config map.
// Use the 'ResourceLoaderGetConfigVars' hook if the variable is not
# TS_ORACLE // session altered to DD-MM-YYYY HH24:MI:SS.FF6
$strtime = preg_replace( '/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
str_replace( '+00:00', 'UTC', $ts ) );
- } elseif ( preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.*\d*)?Z$/', $ts, $da ) ) {
+ } elseif ( preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.*\d*)?Z?$/', $ts, $da ) ) {
# TS_ISO_8601
- } elseif ( preg_match( '/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(?:\.*\d*)?Z$/', $ts, $da ) ) {
+ } elseif ( preg_match( '/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(?:\.*\d*)?Z?$/', $ts, $da ) ) {
#TS_ISO_8601_BASIC
} elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d*[\+\- ](\d\d)$/', $ts, $da ) ) {
# TS_POSTGRES
var $mRedirect = null; // /< Is the article at this title a redirect?
var $mNotificationTimestamp = array(); // /< Associative array of user ID -> timestamp/false
var $mHasSubpage; // /< Whether a page has any subpages
+ private $mPageLanguage = false; // /< The (string) language code of the page's language and content code.
// @}
/**
$this->mLatestID = false;
$this->mContentModel = false;
$this->mEstimateRevisions = null;
+ $this->mPageLanguage = false;
}
/**
* @return Language
*/
public function getPageLanguage() {
- global $wgLang;
+ global $wgLang, $wgLanguageCode;
+ wfProfileIn( __METHOD__ );
if ( $this->isSpecialPage() ) {
// special pages are in the user language
+ wfProfileOut( __METHOD__ );
return $wgLang;
}
- //TODO: use the LinkCache to cache this! Note that this may depend on user settings, so the cache should be only per-request.
- //NOTE: ContentHandler::getPageLanguage() may need to load the content to determine the page language!
- $contentHandler = ContentHandler::getForTitle( $this );
- $pageLang = $contentHandler->getPageLanguage( $this );
-
- return wfGetLangObj( $pageLang );
+ if ( !$this->mPageLanguage || $this->mPageLanguage[1] !== $wgLanguageCode ) {
+ // Note that this may depend on user settings, so the cache should be only per-request.
+ // NOTE: ContentHandler::getPageLanguage() may need to load the content to determine the page language!
+ // Checking $wgLanguageCode hasn't changed for the benefit of unit tests.
+ $contentHandler = ContentHandler::getForTitle( $this );
+ $langObj = wfGetLangObj( $contentHandler->getPageLanguage( $this ) );
+ $this->mPageLanguage = array( $langObj->getCode(), $wgLanguageCode );
+ } else {
+ $langObj = wfGetLangObj( $this->mPageLanguage[0] );
+ }
+ wfProfileOut( __METHOD__ );
+ return $langObj;
}
/**
$updates = $this->getDeletionUpdates( $content );
DataUpdate::runUpdates( $updates );
+ // Reparse any pages transcluding this page
+ LinksUpdate::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks' );
+
// Clear caches
WikiPage::onArticleDelete( $this->mTitle );
$undo_content = $undo->getContent();
$undoafter_content = $undoafter->getContent();
+ if ( !$undo_content || !$undoafter_content ) {
+ return false; // no content to undo
+ }
+
$this->checkModelID( $cur_content->getModel() );
$this->checkModelID( $undo_content->getModel() );
$this->checkModelID( $undoafter_content->getModel() );
*/
protected $fileHandle = null;
+ /**
+ * @since 1.22
+ * @var Process cache of VIEWs names in the database
+ */
+ protected $allViews = null;
+
# ------------------------------------------------------------------------------
# Accessors
# ------------------------------------------------------------------------------
throw new MWException( 'DatabaseBase::listTables is not implemented in descendant class' );
}
+ /**
+ * Reset the views process cache set by listViews()
+ * @since 1.22
+ */
+ final public function clearViewsCache() {
+ $this->allViews = null;
+ }
+
+ /**
+ * Lists all the VIEWs in the database
+ *
+ * For caching purposes the list of all views should be stored in
+ * $this->allViews. The process cache can be cleared with clearViewsCache()
+ *
+ * @param string $prefix Only show VIEWs with this prefix, eg. unit_test_
+ * @param string $fname Name of calling function
+ * @throws MWException
+ * @since 1.22
+ */
+ public function listViews( $prefix = null, $fname = __METHOD__ ) {
+ throw new MWException( 'DatabaseBase::listViews is not implemented in descendant class' );
+ }
+
+ /**
+ * Differentiates between a TABLE and a VIEW
+ *
+ * @param $name string: Name of the database-structure to test.
+ * @throws MWException
+ * @since 1.22
+ */
+ public function isView( $name ) {
+ throw new MWException( 'DatabaseBase::isView is not implemented in descendant class' );
+ }
+
/**
* Convert a timestamp in one of the formats accepted by wfTimestamp()
* to the format used for inserting into timestamp fields in this DBMS.
return $status;
}
+ /**
+ * Lists VIEWs in the database
+ *
+ * @param string $prefix Only show VIEWs with this prefix, eg.
+ * unit_test_, or $wgDBprefix. Default: null, would return all views.
+ * @param string $fname Name of calling function
+ * @return array
+ * @since 1.22
+ */
+ public function listViews( $prefix = null, $fname = __METHOD__ ) {
+
+ if ( !isset( $this->allViews ) ) {
+
+ // The name of the column containing the name of the VIEW
+ $propertyName = 'Tables_in_' . $this->mDBname;
+
+ // Query for the VIEWS
+ $result = $this->query( 'SHOW FULL TABLES WHERE TABLE_TYPE = "VIEW"' );
+ $this->allViews = array();
+ while ( ($row = $this->fetchRow($result)) !== false ) {
+ array_push( $this->allViews, $row[$propertyName] );
+ }
+ }
+
+ if ( is_null($prefix) || $prefix === '' ) {
+ return $this->allViews;
+ }
+
+ $filteredViews = array();
+ foreach ( $this->allViews as $viewName ) {
+ // Does the name of this VIEW start with the table-prefix?
+ if ( strpos( $viewName, $prefix ) === 0 ) {
+ array_push( $filteredViews, $viewName );
+ }
+ }
+ return $filteredViews;
+ }
+
+ /**
+ * Differentiates between a TABLE and a VIEW.
+ *
+ * @param $name string: Name of the TABLE/VIEW to test
+ * @return bool
+ * @since 1.22
+ */
+ public function isView( $name, $prefix = null ) {
+ return in_array( $name, $this->listViews( $prefix ) );
+ }
+
}
$srcObj = $contObj->get_object( $srcRel, $this->headersFromParams( $params ) );
$this->addMissingMetadata( $srcObj, $params['src'] );
$stat = array(
- // Convert dates like "Tue, 03 Jan 2012 22:01:04 GMT" to TS_MW
- 'mtime' => wfTimestamp( TS_MW, $srcObj->last_modified ),
+ // Convert various random Swift dates to TS_MW
+ 'mtime' => $this->convertSwiftDate( $srcObj->last_modified, TS_MW ),
'size' => (int)$srcObj->content_length,
'sha1' => $srcObj->getMetadataValue( 'Sha1base36' )
);
return $stat;
}
+ /**
+ * Convert dates like "Tue, 03 Jan 2012 22:01:04 GMT"/"2013-05-11T07:37:27.678360Z".
+ * Dates might also come in like "2013-05-11T07:37:27.678360" from Swift listings,
+ * missing the timezone suffix (though Ceph RGW does not appear to have this bug).
+ *
+ * @param string $ts
+ * @param int $format Output format (TS_* constant)
+ * @return string
+ * @throws MWException
+ */
+ protected function convertSwiftDate( $ts, $format = TS_MW ) {
+ $timestamp = new MWTimestamp( $ts );
+ return $timestamp->getTimestamp( $format );
+ }
+
/**
* Fill in any missing object metadata and save it to Swift
*
$object = current( $cfObjects );
$path = "{$storageDir}/" . substr( $object->name, $suffixStart );
$val = array(
- // Convert dates like "Tue, 03 Jan 2012 22:01:04 GMT" to TS_MW
- 'mtime' => wfTimestamp( TS_MW, $object->last_modified ),
+ // Convert various random Swift dates to TS_MW
+ 'mtime' => $this->convertSwiftDate( $object->last_modified, TS_MW ),
'size' => (int)$object->content_length,
'latest' => false // eventually consistent
);
}
/**
- * Publishes the log entry.
- * @param int $newId id of the log entry.
- * @param string $to rcandudp (default), rc, udp
+ * Get a RecentChanges object for the log entry
+ * @param int $newId
+ * @return RecentChange
+ * @since 1.23
*/
- public function publish( $newId, $to = 'rcandudp' ) {
- $log = new LogPage( $this->getType() );
- if ( $log->isRestricted() ) {
- return;
- }
-
+ public function getRecentChange( $newId = 0 ) {
$formatter = LogFormatter::newFromEntry( $this );
$context = RequestContext::newExtraneousContext( $this->getTarget() );
$formatter->setContext( $context );
$ip = $user->getName();
}
}
- $rc = RecentChange::newLogEntry(
+ return RecentChange::newLogEntry(
$this->getTimestamp(),
$logpage,
$user,
$formatter->getIRCActionComment() // Used for IRC feeds
);
+ }
+
+ /**
+ * Publishes the log entry.
+ * @param int $newId id of the log entry.
+ * @param string $to rcandudp (default), rc, udp
+ */
+ public function publish( $newId, $to = 'rcandudp' ) {
+ $log = new LogPage( $this->getType() );
+ if ( $log->isRestricted() ) {
+ return;
+ }
+
+ $rc = $this->getRecentChange( $newId );
+
if ( $to === 'rc' || $to === 'rcandudp' ) {
$rc->save( 'pleasedontudp' );
}
} else {
$out->addWikiText( $status->getWikiText( 'confirmemail_sendfailed' ) );
}
+ } elseif ( $user->isEmailConfirmed() ) {
+ // date and time are separate parameters to facilitate localisation.
+ // $time is kept for backward compat reasons.
+ // 'emailauthenticated' is also used in SpecialPreferences.php
+ $lang = $this->getLanguage();
+ $emailAuthenticated = $user->getEmailAuthenticationTimestamp();
+ $time = $lang->userTimeAndDate( $emailAuthenticated, $user );
+ $d = $lang->userDate( $emailAuthenticated, $user );
+ $t = $lang->userTime( $emailAuthenticated, $user );
+ $out->addWikiMsg( 'emailauthenticated', $time, $d, $t );
} else {
- if ( $user->isEmailConfirmed() ) {
- // date and time are separate parameters to facilitate localisation.
- // $time is kept for backward compat reasons.
- // 'emailauthenticated' is also used in SpecialPreferences.php
- $lang = $this->getLanguage();
- $emailAuthenticated = $user->getEmailAuthenticationTimestamp();
- $time = $lang->userTimeAndDate( $emailAuthenticated, $user );
- $d = $lang->userDate( $emailAuthenticated, $user );
- $t = $lang->userTime( $emailAuthenticated, $user );
- $out->addWikiMsg( 'emailauthenticated', $time, $d, $t );
- }
-
if ( $user->isEmailConfirmationPending() ) {
$out->wrapWikiMsg(
"<div class=\"error mw-confirmemail-pending\">\n$1\n</div>",
break;
}
}
+
return $i;
}
}
return new CdbReader_DBA( $fileName );
} else {
wfDebug( "Warning: no dba extension found, using emulation.\n" );
+
return new CdbReader_PHP( $fileName );
}
}
if ( !in_array( 'cdb', $handlers ) || !in_array( 'cdb_make', $handlers ) ) {
return false;
}
+
return true;
}
return new CdbWriter_DBA( $fileName );
} else {
wfDebug( "Warning: no dba extension found, using emulation.\n" );
+
return new CdbWriter_PHP( $fileName );
}
}
public static function unsignedMod( $a, $b ) {
if ( $a & 0x80000000 ) {
$m = ( $a & 0x7fffffff ) % $b + 2 * ( 0x40000000 % $b );
+
return $m % $b;
} else {
return $a % $b;
$h ^= ord( $s[$i] );
$h &= 0xffffffff;
}
+
return $h;
}
}
*/
protected function match( $key, $pos ) {
$buf = $this->read( strlen( $key ), $pos );
+
return $buf === $key;
}
throw new MWException(
'Read from CDB file failed, file "' . $this->fileName . '" may be corrupted.' );
}
+
return $buf;
}
throw new MWException(
'Error in CDB file "' . $this->fileName . '", integer too big.' );
}
+
return $data[1];
}
*/
protected function unpackSigned( $s ) {
$data = unpack( 'va/vb', $s );
+
return $data['a'] | ( $data['b'] << 16 );
}
// Found
$this->dlen = $this->unpack31( substr( $buf, 4 ) );
$this->dpos = $pos + 8 + $keyLen;
+
return true;
}
}
}
+
return false;
}
*/
protected function find( $key ) {
$this->findStart();
+
return $this->findNext( $key );
}
}
// Calculate the number of items that will be in each hashtable
$counts = array_fill( 0, 256, 0 );
foreach ( $this->hplist as $item ) {
- ++ $counts[255 & $item['h']];
+ ++$counts[255 & $item['h']];
}
// Fill in $starts with the *end* indexes
} catch ( ConfEditorParseError $e ) {
return $e->getMessage() . "\n" . $e->highlight( $text );
}
+
return "OK";
}
$key = isset( $op['key'] ) ? $op['key'] : null;
switch ( $type ) {
- case 'delete':
- list( $start, $end ) = $this->findDeletionRegion( $path );
- $this->replaceSourceRegion( $start, $end, false );
- break;
- case 'set':
- if ( isset( $this->pathInfo[$path] ) ) {
- list( $start, $end ) = $this->findValueRegion( $path );
- $encValue = $value; // var_export( $value, true );
- $this->replaceSourceRegion( $start, $end, $encValue );
+ case 'delete':
+ list( $start, $end ) = $this->findDeletionRegion( $path );
+ $this->replaceSourceRegion( $start, $end, false );
break;
- }
- // No existing path, fall through to append
- $slashPos = strrpos( $path, '/' );
- $key = var_export( substr( $path, $slashPos + 1 ), true );
- $path = substr( $path, 0, $slashPos );
- // Fall through
- case 'append':
- // Find the last array element
- $lastEltPath = $this->findLastArrayElement( $path );
- if ( $lastEltPath === false ) {
- throw new MWException( "Can't find any element of array \"$path\"" );
- }
- $lastEltInfo = $this->pathInfo[$lastEltPath];
+ case 'set':
+ if ( isset( $this->pathInfo[$path] ) ) {
+ list( $start, $end ) = $this->findValueRegion( $path );
+ $encValue = $value; // var_export( $value, true );
+ $this->replaceSourceRegion( $start, $end, $encValue );
+ break;
+ }
+ // No existing path, fall through to append
+ $slashPos = strrpos( $path, '/' );
+ $key = var_export( substr( $path, $slashPos + 1 ), true );
+ $path = substr( $path, 0, $slashPos );
+ // Fall through
+ case 'append':
+ // Find the last array element
+ $lastEltPath = $this->findLastArrayElement( $path );
+ if ( $lastEltPath === false ) {
+ throw new MWException( "Can't find any element of array \"$path\"" );
+ }
+ $lastEltInfo = $this->pathInfo[$lastEltPath];
- // Has it got a comma already?
- if ( strpos( $lastEltPath, '@extra' ) === false && !$lastEltInfo['hasComma'] ) {
- // No comma, insert one after the value region
- list( , $end ) = $this->findValueRegion( $lastEltPath );
- $this->replaceSourceRegion( $end - 1, $end - 1, ',' );
- }
+ // Has it got a comma already?
+ if ( strpos( $lastEltPath, '@extra' ) === false && !$lastEltInfo['hasComma'] ) {
+ // No comma, insert one after the value region
+ list( , $end ) = $this->findValueRegion( $lastEltPath );
+ $this->replaceSourceRegion( $end - 1, $end - 1, ',' );
+ }
- // Make the text to insert
- list( $start, $end ) = $this->findDeletionRegion( $lastEltPath );
+ // Make the text to insert
+ list( $start, $end ) = $this->findDeletionRegion( $lastEltPath );
- if ( $key === null ) {
- list( $indent, ) = $this->getIndent( $start );
- $textToInsert = "$indent$value,";
- } else {
- list( $indent, $arrowIndent ) =
- $this->getIndent( $start, $key, $lastEltInfo['arrowByte'] );
- $textToInsert = "$indent$key$arrowIndent=> $value,";
- }
- $textToInsert .= ( $indent === false ? ' ' : "\n" );
+ if ( $key === null ) {
+ list( $indent, ) = $this->getIndent( $start );
+ $textToInsert = "$indent$value,";
+ } else {
+ list( $indent, $arrowIndent ) =
+ $this->getIndent( $start, $key, $lastEltInfo['arrowByte'] );
+ $textToInsert = "$indent$key$arrowIndent=> $value,";
+ }
+ $textToInsert .= ( $indent === false ? ' ' : "\n" );
- // Insert the item
- $this->replaceSourceRegion( $end, $end, $textToInsert );
- break;
- case 'insert':
- // Find first array element
- $firstEltPath = $this->findFirstArrayElement( $path );
- if ( $firstEltPath === false ) {
- throw new MWException( "Can't find array element of \"$path\"" );
- }
- list( $start, ) = $this->findDeletionRegion( $firstEltPath );
- $info = $this->pathInfo[$firstEltPath];
-
- // Make the text to insert
- if ( $key === null ) {
- list( $indent, ) = $this->getIndent( $start );
- $textToInsert = "$indent$value,";
- } else {
- list( $indent, $arrowIndent ) =
- $this->getIndent( $start, $key, $info['arrowByte'] );
- $textToInsert = "$indent$key$arrowIndent=> $value,";
- }
- $textToInsert .= ( $indent === false ? ' ' : "\n" );
+ // Insert the item
+ $this->replaceSourceRegion( $end, $end, $textToInsert );
+ break;
+ case 'insert':
+ // Find first array element
+ $firstEltPath = $this->findFirstArrayElement( $path );
+ if ( $firstEltPath === false ) {
+ throw new MWException( "Can't find array element of \"$path\"" );
+ }
+ list( $start, ) = $this->findDeletionRegion( $firstEltPath );
+ $info = $this->pathInfo[$firstEltPath];
- // Insert the item
- $this->replaceSourceRegion( $start, $start, $textToInsert );
- break;
- default:
- throw new MWException( "Unrecognised operation: \"$type\"" );
+ // Make the text to insert
+ if ( $key === null ) {
+ list( $indent, ) = $this->getIndent( $start );
+ $textToInsert = "$indent$value,";
+ } else {
+ list( $indent, $arrowIndent ) =
+ $this->getIndent( $start, $key, $info['arrowByte'] );
+ $textToInsert = "$indent$key$arrowIndent=> $value,";
+ }
+ $textToInsert .= ( $indent === false ? ' ' : "\n" );
+
+ // Insert the item
+ $this->replaceSourceRegion( $start, $start, $textToInsert );
+ break;
+ default:
+ throw new MWException( "Unrecognised operation: \"$type\"" );
}
}
"Sorry, ConfEditor broke the file during editing and it won't parse anymore: " .
$e->getMessage() );
}
+
return $out;
}
$this->setVar( $vars, $parentPath, $name,
$this->parseScalar( $value ) );
}
+
return $vars;
}
if ( substr( $str, 0, 4 ) == 'null' ) {
return null;
}
+
// Must be some kind of numeric value, so let PHP's weak typing
// be useful for a change
return $str;
break;
}
}
+
return array( $regionStart, $regionEnd );
}
if ( $path['valueStartByte'] === false || $path['valueEndByte'] === false ) {
throw new MWException( "Can't find value region for path \"$pathName\"" );
}
+
return array( $path['valueStartByte'], $path['valueEndByte'] );
}
break;
}
}
+
return $extraPath;
}
return $candidatePath;
}
}
+
return false;
}
$arrowIndent = str_repeat( ' ', $arrowIndentLength );
}
}
+
return array( $indent, $arrowIndent );
}
}
switch ( $state ) {
- case 'file':
- $this->expect( T_OPEN_TAG );
- $token = $this->skipSpace();
- if ( $token->isEnd() ) {
- break 2;
- }
- $this->pushState( 'statement', 'file 2' );
- break;
- case 'file 2':
- $token = $this->skipSpace();
- if ( $token->isEnd() ) {
- break 2;
- }
- $this->pushState( 'statement', 'file 2' );
- break;
- case 'statement':
- $token = $this->skipSpace();
- if ( !$this->validatePath( $token->text ) ) {
- $this->error( "Invalid variable name \"{$token->text}\"" );
- }
- $this->nextPath( $token->text );
- $this->expect( T_VARIABLE );
- $this->skipSpace();
- $arrayAssign = false;
- if ( $this->currentToken()->type == '[' ) {
- $this->nextToken();
+ case 'file':
+ $this->expect( T_OPEN_TAG );
+ $token = $this->skipSpace();
+ if ( $token->isEnd() ) {
+ break 2;
+ }
+ $this->pushState( 'statement', 'file 2' );
+ break;
+ case 'file 2':
+ $token = $this->skipSpace();
+ if ( $token->isEnd() ) {
+ break 2;
+ }
+ $this->pushState( 'statement', 'file 2' );
+ break;
+ case 'statement':
+ $token = $this->skipSpace();
+ if ( !$this->validatePath( $token->text ) ) {
+ $this->error( "Invalid variable name \"{$token->text}\"" );
+ }
+ $this->nextPath( $token->text );
+ $this->expect( T_VARIABLE );
+ $this->skipSpace();
+ $arrayAssign = false;
+ if ( $this->currentToken()->type == '[' ) {
+ $this->nextToken();
+ $token = $this->skipSpace();
+ if ( !$token->isScalar() ) {
+ $this->error( "expected a string or number for the array key" );
+ }
+ if ( $token->type == T_CONSTANT_ENCAPSED_STRING ) {
+ $text = $this->parseScalar( $token->text );
+ } else {
+ $text = $token->text;
+ }
+ if ( !$this->validatePath( $text ) ) {
+ $this->error( "Invalid associative array name \"$text\"" );
+ }
+ $this->pushPath( $text );
+ $this->nextToken();
+ $this->skipSpace();
+ $this->expect( ']' );
+ $this->skipSpace();
+ $arrayAssign = true;
+ }
+ $this->expect( '=' );
+ $this->skipSpace();
+ $this->startPathValue();
+ if ( $arrayAssign ) {
+ $this->pushState( 'expression', 'array assign end' );
+ } else {
+ $this->pushState( 'expression', 'statement end' );
+ }
+ break;
+ case 'array assign end':
+ case 'statement end':
+ $this->endPathValue();
+ if ( $state == 'array assign end' ) {
+ $this->popPath();
+ }
+ $this->skipSpace();
+ $this->expect( ';' );
+ $this->nextPath( '@extra-' . ( $this->serial++ ) );
+ break;
+ case 'expression':
+ $token = $this->skipSpace();
+ if ( $token->type == T_ARRAY ) {
+ $this->pushState( 'array' );
+ } elseif ( $token->isScalar() ) {
+ $this->nextToken();
+ } elseif ( $token->type == T_VARIABLE ) {
+ $this->nextToken();
+ } else {
+ $this->error( "expected simple expression" );
+ }
+ break;
+ case 'array':
+ $this->skipSpace();
+ $this->expect( T_ARRAY );
+ $this->skipSpace();
+ $this->expect( '(' );
+ $this->skipSpace();
+ $this->pushPath( '@extra-' . ( $this->serial++ ) );
+ if ( $this->isAhead( ')' ) ) {
+ // Empty array
+ $this->pushState( 'array end' );
+ } else {
+ $this->pushState( 'element', 'array end' );
+ }
+ break;
+ case 'array end':
+ $this->skipSpace();
+ $this->popPath();
+ $this->expect( ')' );
+ break;
+ case 'element':
+ $token = $this->skipSpace();
+ // Look ahead to find the double arrow
+ if ( $token->isScalar() && $this->isAhead( T_DOUBLE_ARROW, 1 ) ) {
+ // Found associative element
+ $this->pushState( 'assoc-element', 'element end' );
+ } else {
+ // Not associative
+ $this->nextPath( '@next' );
+ $this->startPathValue();
+ $this->pushState( 'expression', 'element end' );
+ }
+ break;
+ case 'element end':
+ $token = $this->skipSpace();
+ if ( $token->type == ',' ) {
+ $this->endPathValue();
+ $this->markComma();
+ $this->nextToken();
+ $this->nextPath( '@extra-' . ( $this->serial++ ) );
+ // Look ahead to find ending bracket
+ if ( $this->isAhead( ")" ) ) {
+ // Found ending bracket, no continuation
+ $this->skipSpace();
+ } else {
+ // No ending bracket, continue to next element
+ $this->pushState( 'element' );
+ }
+ } elseif ( $token->type == ')' ) {
+ // End array
+ $this->endPathValue();
+ } else {
+ $this->error( "expected the next array element or the end of the array" );
+ }
+ break;
+ case 'assoc-element':
$token = $this->skipSpace();
if ( !$token->isScalar() ) {
$this->error( "expected a string or number for the array key" );
if ( !$this->validatePath( $text ) ) {
$this->error( "Invalid associative array name \"$text\"" );
}
- $this->pushPath( $text );
+ $this->nextPath( $text );
$this->nextToken();
$this->skipSpace();
- $this->expect( ']' );
+ $this->markArrow();
+ $this->expect( T_DOUBLE_ARROW );
$this->skipSpace();
- $arrayAssign = true;
- }
- $this->expect( '=' );
- $this->skipSpace();
- $this->startPathValue();
- if ( $arrayAssign ) {
- $this->pushState( 'expression', 'array assign end' );
- } else {
- $this->pushState( 'expression', 'statement end' );
- }
- break;
- case 'array assign end':
- case 'statement end':
- $this->endPathValue();
- if ( $state == 'array assign end' ) {
- $this->popPath();
- }
- $this->skipSpace();
- $this->expect( ';' );
- $this->nextPath( '@extra-' . ( $this->serial++ ) );
- break;
- case 'expression':
- $token = $this->skipSpace();
- if ( $token->type == T_ARRAY ) {
- $this->pushState( 'array' );
- } elseif ( $token->isScalar() ) {
- $this->nextToken();
- } elseif ( $token->type == T_VARIABLE ) {
- $this->nextToken();
- } else {
- $this->error( "expected simple expression" );
- }
- break;
- case 'array':
- $this->skipSpace();
- $this->expect( T_ARRAY );
- $this->skipSpace();
- $this->expect( '(' );
- $this->skipSpace();
- $this->pushPath( '@extra-' . ( $this->serial++ ) );
- if ( $this->isAhead( ')' ) ) {
- // Empty array
- $this->pushState( 'array end' );
- } else {
- $this->pushState( 'element', 'array end' );
- }
- break;
- case 'array end':
- $this->skipSpace();
- $this->popPath();
- $this->expect( ')' );
- break;
- case 'element':
- $token = $this->skipSpace();
- // Look ahead to find the double arrow
- if ( $token->isScalar() && $this->isAhead( T_DOUBLE_ARROW, 1 ) ) {
- // Found associative element
- $this->pushState( 'assoc-element', 'element end' );
- } else {
- // Not associative
- $this->nextPath( '@next' );
$this->startPathValue();
- $this->pushState( 'expression', 'element end' );
- }
- break;
- case 'element end':
- $token = $this->skipSpace();
- if ( $token->type == ',' ) {
- $this->endPathValue();
- $this->markComma();
- $this->nextToken();
- $this->nextPath( '@extra-' . ( $this->serial++ ) );
- // Look ahead to find ending bracket
- if ( $this->isAhead( ")" ) ) {
- // Found ending bracket, no continuation
- $this->skipSpace();
- } else {
- // No ending bracket, continue to next element
- $this->pushState( 'element' );
- }
- } elseif ( $token->type == ')' ) {
- // End array
- $this->endPathValue();
- } else {
- $this->error( "expected the next array element or the end of the array" );
- }
- break;
- case 'assoc-element':
- $token = $this->skipSpace();
- if ( !$token->isScalar() ) {
- $this->error( "expected a string or number for the array key" );
- }
- if ( $token->type == T_CONSTANT_ENCAPSED_STRING ) {
- $text = $this->parseScalar( $token->text );
- } else {
- $text = $token->text;
- }
- if ( !$this->validatePath( $text ) ) {
- $this->error( "Invalid associative array name \"$text\"" );
- }
- $this->nextPath( $text );
- $this->nextToken();
- $this->skipSpace();
- $this->markArrow();
- $this->expect( T_DOUBLE_ARROW );
- $this->skipSpace();
- $this->startPathValue();
- $this->pushState( 'expression' );
- break;
+ $this->pushState( 'expression' );
+ break;
}
}
if ( count( $this->stateStack ) ) {
} else {
$this->currentToken = $this->newTokenObj( $this->tokens[$this->pos] );
}
+
return $this->currentToken;
}
$this->lineNum = 1;
$this->colNum = 1;
$this->byteNum = 0;
+
return $this->currentToken;
}
}
$this->prevToken = $this->currentToken;
$this->setPos( $this->pos + 1 );
+
return $this->currentToken;
}
while ( $this->currentToken && $this->currentToken->isSkip() ) {
$this->nextToken();
}
+
return $this->currentToken;
}
return false;
}
}
+
return false;
}
*/
class ConfEditorParseError extends MWException {
var $lineNum, $colNum;
+
function __construct( $editor, $msg ) {
$this->lineNum = $editor->lineNum;
$this->colNum = $editor->colNum;
return "$line\n" . str_repeat( ' ', $this->colNum - 1 ) . "^\n";
}
}
+
return '';
}
-
}
/**
* @param array $map (location => weight)
*/
public function __construct( array $map ) {
- $map = array_filter( $map, function( $w ) { return $w > 0; } );
+ $map = array_filter( $map, function ( $w ) {
+ return $w > 0;
+ } );
if ( !count( $map ) ) {
throw new MWException( "Ring is empty or all weights are zero." );
}
*/
public function getLocation( $item ) {
$locations = $this->getLocations( $item, 1 );
+
return $locations[0];
}
}
$locations[] = $location;
}
+
return $locations;
}
if ( count( $map ) ) {
return new self( $map );
}
+
return false;
}
}
}
// Remove leading zeros from each bloc as needed
$ip = preg_replace( '/(^|:)0+(' . RE_IPV6_WORD . ')/', '$1$2', $ip );
+
return $ip;
}
// Convert to lower case to make it more readable
$ip = strtolower( $ip );
}
+
return $ip;
}
return false;
}
}
+
// Plain hostname
return array( $both, false );
}
}
// NO leading zeroes
$ip_oct = preg_replace( '/(^|:)0+(' . RE_IPV6_WORD . ')/', '$1$2', $ip_oct );
+
return $ip_oct;
}
}
$s .= base_convert( substr( $ip_hex, $i * 2, 2 ), 16, 10 );
}
+
return $s;
}
return false;
}
}
+
return true;
}
return false;
}
}
+
return true;
}
$n = wfBaseConvert( $n, 10, 16, 8, false );
}
}
+
return $n;
}
foreach ( explode( ':', $ip ) as $v ) {
$r_ip .= str_pad( $v, 4, 0, STR_PAD_LEFT );
}
+
return $r_ip;
}
}
}
}
+
return $n;
}
$network = false;
$bits = false;
}
+
return array( $network, $bits );
}
* 1.2.3.4 - 1.2.3.5 Explicit range
* 1.2.3.4 Single IP
*
- * 2001:0db8:85a3::7344/96 CIDR
+ * 2001:0db8:85a3::7344/96 CIDR
* 2001:0db8:85a3::7344 - 2001:0db8:85a3::7344 Explicit range
- * 2001:0db8:85a3::7344 Single IP
+ * 2001:0db8:85a3::7344 Single IP
* @param string $range IP range
* @return array(string, string)
*/
$network = false;
$bits = false;
}
+
return array( $network, (int)$bits );
}
* start and end of the range in hexadecimal. For IPv6.
*
* Formats are:
- * 2001:0db8:85a3::7344/96 CIDR
+ * 2001:0db8:85a3::7344/96 CIDR
* 2001:0db8:85a3::7344 - 2001:0db8:85a3::7344 Explicit range
- * 2001:0db8:85a3::7344/96 Single IP
+ * 2001:0db8:85a3::7344/96 Single IP
*
* @param $range
*
$start = "v6-$start";
$end = "v6-$end";
}
- // Explicit range notation...
+ // Explicit range notation...
} elseif ( strpos( $range, '-' ) !== false ) {
list( $start, $end ) = array_map( 'trim', explode( '-', $range, 2 ) );
$start = self::toUnsigned6( $start );
public static function isInRange( $addr, $range ) {
$hexIP = self::toHex( $addr );
list( $start, $end ) = self::parseRange( $range );
+
return ( strcmp( $hexIP, $start ) >= 0 &&
strcmp( $hexIP, $end ) <= 0 );
}
return $m[1];
}
if ( preg_match( '/^' . RE_IPV6_V4_PREFIX . RE_IPV6_WORD .
- ':' . RE_IPV6_WORD . '$/i', $addr, $m ) )
- {
+ ':' . RE_IPV6_WORD . '$/i', $addr, $m )
+ ) {
return long2ip( ( hexdec( $m[1] ) << 16 ) + hexdec( $m[2] ) );
}
if ( $bits === false ) {
return $start; // wasn't actually a range
}
+
return "$start/$bits";
}
}
"(time-taken=" . ( $timeTaken * 1000 ) . "ms, " .
"iterations=$iterations, " .
"time-per-iteration=" . ( $timeTaken / $iterations * 1e6 ) . "us)\n" );
+
return $data;
}
// Generate a new random state based on the initial random state or previous
// random state by combining it with clock drift
$state = $this->driftHash( $state );
+
return $state;
}
if ( in_array( $algorithm, $algos ) ) {
$this->algo = $algorithm;
wfDebug( __METHOD__ . ": Using the {$this->algo} hash algorithm.\n" );
+
return $this->algo;
}
}
if ( is_null( $this->hashLength ) ) {
$this->hashLength = strlen( $this->hash( '' ) );
}
+
return $this->hashLength;
}
if ( is_null( $this->strong ) ) {
throw new MWException( __METHOD__ . ' called before generation of random data' );
}
+
return $this->strong;
}
wfDebug( __METHOD__ . ": " . strlen( $buffer ) . " bytes of randomness leftover in the buffer.\n" );
wfProfileOut( __METHOD__ );
+
return $generated;
}
$bytes = ceil( $chars / 2 );
// Generate the data and then convert it to a hex string
$hex = bin2hex( $this->generate( $bytes, $forceStrong ) );
+
// A bit of paranoia here, the caller asked for a specific length of string
// here, and it's possible (eg when given an odd number) that we may actually
// have at least 1 char more than they asked for. Just in case they made this
if ( is_null( self::$singleton ) ) {
self::$singleton = new self;
}
+
return self::$singleton;
}
public static function generateHex( $chars, $forceStrong = false ) {
return self::singleton()->realGenerateHex( $chars, $forceStrong );
}
-
}
public static function call( $callback ) {
wfDeprecated( __METHOD__, '1.22' );
$args = func_get_args();
+
return call_user_func_array( 'call_user_func', $args );
}
*/
public static function callArray( $callback, $argsarams ) {
wfDeprecated( __METHOD__, '1.22' );
+
return call_user_func_array( $callback, $argsarams );
}
}
$ref = new ReflectionClass( $class );
+
return $ref->newInstanceArgs( $args );
}
-
}
if ( $ok ) {
$this->cache['current'] = $value;
}
+
return $ok;
}
public function key() {
$this->init();
+
return parent::key();
}
public function valid() {
$this->init();
+
return parent::valid();
}
return false;
}
}
+
return true;
}
$output .= $replace . substr( $s, $endDelimPos + strlen( $endDelim ) );
}
}
+
return $output;
}
$m = array();
while ( $inputPos < strlen( $subject ) &&
- preg_match( "!($encStart)|($encEnd)!S$flags", $subject, $m, PREG_OFFSET_CAPTURE, $inputPos ) )
- {
+ preg_match( "!($encStart)|($encEnd)!S$flags", $subject, $m, PREG_OFFSET_CAPTURE, $inputPos )
+ ) {
$tokenOffset = $m[0][1];
if ( $m[1][0] != '' ) {
if ( $foundStart &&
- $strcmp( $endDelim, substr( $subject, $tokenOffset, $endLength ) ) == 0 )
- {
+ $strcmp( $endDelim, substr( $subject, $tokenOffset, $endLength ) ) == 0
+ ) {
# An end match is present at the same location
$tokenType = 'end';
$tokenLength = $endLength;
$output .= call_user_func( $callback, array(
substr( $subject, $outputPos, $tokenOffset + $tokenLength - $outputPos ),
substr( $subject, $contentPos, $tokenOffset - $contentPos )
- ));
+ ) );
$foundStart = false;
} else {
# Non-matching end, write it out
if ( $outputPos < strlen( $subject ) ) {
$output .= substr( $subject, $outputPos );
}
+
return $output;
}
*/
static function delimiterReplace( $startDelim, $endDelim, $replace, $subject, $flags = '' ) {
$replacer = new RegexlikeReplacer( $replace );
+
return self::delimiterReplaceCallback( $startDelim, $endDelim,
$replacer->cb(), $subject, $flags );
}
static function escapeRegexReplacement( $string ) {
$string = str_replace( '\\', '\\\\', $string );
$string = str_replace( '$', '\\$', $string );
+
return $string;
}
foreach ( $matches as $i => $match ) {
$pairs["\$$i"] = $match;
}
+
return strtr( $this->r, $pairs );
}
-
}
/**
$result = strtr( $subject, $this->data );
wfProfileOut( __METHOD__ . '-strtr' );
}
+
return $result;
}
}
}
}
$this->refreshCurrent();
+
return $this->current;
}
if ( self::$instance === null ) {
self::$instance = new self();
}
+
return self::$instance;
}
}
$gen = self::singleton();
$time = $gen->getTimestampAndDelay( 'lockFile88', 1, 1024 );
+
return wfBaseConvert( $gen->getTimestampedID88( $time ), 2, $base );
}
if ( strlen( $id_bin ) !== 88 ) {
throw new MWException( "Detected overflow for millisecond timestamp." );
}
+
return $id_bin;
}
}
$gen = self::singleton();
$time = $gen->getTimestampAndDelay( 'lockFile128', 16384, 1048576 );
+
return wfBaseConvert( $gen->getTimestampedID128( $time ), 2, $base );
}
if ( strlen( $id_bin ) !== 128 ) {
throw new MWException( "Detected overflow for millisecond timestamp." );
}
+
return $id_bin;
}
throw new MWException( __METHOD__ .
': sorry, this function doesn\'t work after the year 144680' );
}
+
return substr( wfBaseConvert( $ts, 10, 2, 46 ), -46 );
}
*/
protected static function millitime() {
list( $msec, $sec ) = explode( ' ', microtime() );
+
return array( (int)$sec, (int)( $msec * 1000 ) );
}
*/
public static function read( $fileName, $callback, $options = array() ) {
$zdr = new self( $fileName, $callback, $options );
+
return $zdr->execute();
}
} else {
if ( $this->eocdr['CD size'] == 0xffffffff
|| $this->eocdr['CD offset'] == 0xffffffff
- || $this->eocdr['CD entries total'] == 0xffff )
- {
+ || $this->eocdr['CD entries total'] == 0xffff
+ ) {
$this->error( 'zip-unsupported', 'Central directory header indicates ZIP64, ' .
'but we are in legacy mode. Rejecting this upload is necessary to avoid ' .
'opening vulnerabilities on clients using OpenJDK 7 or later.' );
}
fclose( $this->file );
+
return $status;
}
$this->error( 'zip-bad', 'trailing bytes after the end of the file comment' );
}
if ( $this->eocdr['disk'] !== 0
- || $this->eocdr['CD start disk'] !== 0 )
- {
+ || $this->eocdr['CD start disk'] !== 0
+ ) {
$this->error( 'zip-unsupported', 'more than one disk (in EOCDR)' );
}
$this->eocdr += $this->unpack(
*/
function readZip64EndOfCentralDirectoryRecord() {
if ( $this->eocdr64Locator['eocdr64 start disk'] != 0
- || $this->eocdr64Locator['number of disks'] != 0 )
- {
+ || $this->eocdr64Locator['number of disks'] != 0
+ ) {
$this->error( 'zip-unsupported', 'more than one disk (in EOCDR64 locator)' );
}
$this->error( 'zip-bad', 'wrong signature on Zip64 end of central directory record' );
}
if ( $data['disk'] !== 0
- || $data['CD start disk'] !== 0 )
- {
+ || $data['CD start disk'] !== 0
+ ) {
$this->error( 'zip-unsupported', 'more than one disk (in EOCDR64)' );
}
}
$this->error( 'zip-bad', 'the central directory does not immediately precede the end ' .
'of central directory record' );
}
+
return array( $offset, $size );
}
$endPos = $this->eocdr['position'];
if ( $size == 0xffffffff
|| $offset == 0xffffffff
- || $numEntries == 0xffff )
- {
+ || $numEntries == 0xffff
+ ) {
$this->readZip64EndOfCentralDirectoryLocator();
if ( isset( $this->eocdr64Locator['eocdr64 offset'] ) ) {
$this->error( 'zip-bad', 'the central directory does not immediately precede the end ' .
'of central directory record' );
}
+
return array( $offset, $size );
}
$pos += $this->getStructSize( $variableInfo );
if ( $this->zip64 && (
- $data['compressed size'] == 0xffffffff
- || $data['uncompressed size'] == 0xffffffff
- || $data['local header offset'] == 0xffffffff ) )
- {
+ $data['compressed size'] == 0xffffffff
+ || $data['uncompressed size'] == 0xffffffff
+ || $data['local header offset'] == 0xffffffff )
+ ) {
$zip64Data = $this->unpackZip64Extra( $data['extra field'] );
if ( $zip64Data ) {
$data = $zip64Data + $data;
// Convert the character set in the file name
if ( !function_exists( 'iconv' )
- || $this->testBit( $data['general bits'], self::GENERAL_UTF8 ) )
- {
+ || $this->testBit( $data['general bits'], self::GENERAL_UTF8 )
+ ) {
$name = $data['name'];
} else {
$name = iconv( 'CP437', 'UTF-8', $data['name'] );
$stat = fstat( $this->file );
$this->fileLength = $stat['size'];
}
+
return $this->fileLength;
}
$bytePos = $segIndex * self::SEGSIZE;
if ( $bytePos >= $this->getFileLength() ) {
$this->buffer[$segIndex] = '';
+
return '';
}
if ( fseek( $this->file, $bytePos ) ) {
}
$this->buffer[$segIndex] = $seg;
}
+
return $this->buffer[$segIndex];
}
$size += $type;
}
}
+
return $size;
}
if ( is_array( $type ) ) {
list( $typeName, $fieldSize ) = $type;
switch ( $typeName ) {
- case 'string':
- $data[$key] = substr( $string, $pos, $fieldSize );
- $pos += $fieldSize;
- break;
- default:
- throw new MWException( __METHOD__ . ": invalid type \"$typeName\"" );
+ case 'string':
+ $data[$key] = substr( $string, $pos, $fieldSize );
+ $pos += $fieldSize;
+ break;
+ default:
+ throw new MWException( __METHOD__ . ": invalid type \"$typeName\"" );
}
} else {
// Unsigned little-endian integer
'history_short' => 'Riwayat',
'updatedmarker' => 'geuubah yoh seunaweue keuneulheueh lon phon kon',
'printableversion' => 'Seunalén rakam',
-'permalink' => 'Seuneumat teutap',
+'permalink' => 'Peunawôt teutap',
'print' => 'Rakam',
'view' => 'Beuet',
'edit' => 'Andam',
# Recent changes linked
'recentchangeslinked' => 'Neuubah meuhubông',
'recentchangeslinked-feed' => 'Neuubah meuhubông',
-'recentchangeslinked-toolbox' => 'Neuubah meuhubông',
+'recentchangeslinked-toolbox' => "Neuubah teukaw'èt",
'recentchangeslinked-title' => 'Neuubah nyang meuhubông ngön $1',
'recentchangeslinked-summary' => "Nyoë nakeuh dapeuta neuubah nyang geupeugèt ban-ban nyoë keu on-on nyang meuhubông nibak ôn ka kusuih (atawa keu anggèëta kawan kusuih).
Ôn-ôn bak [[Special:Watchlist|keunalon droeneuh]] geucitak '''teubay'''.",
'specialloguserlabel' => 'Ureuëng nguy:',
'speciallogtitlelabel' => 'Nan:',
'log' => 'Log',
-'all-logs-page' => 'Ban dum log',
+'all-logs-page' => 'Ban dum log umom',
# Special:AllPages
'allpages' => 'Dapeuta ôn',
'sp-contributions-submit' => 'Mita',
# What links here
-'whatlinkshere' => 'Hubông balék',
+'whatlinkshere' => 'Peunawôt balék',
'whatlinkshere-title' => 'Ôn nyang na neuhubông u $1',
'whatlinkshere-page' => 'Ôn:',
'linkshere' => "Ôn-ôn nyoë meuhubông u '''[[:$1]]''':",
'tooltip-undo' => 'Peuriwang geunantoë nyoë ngön peuhah plôk neu’andam ngön cara eu dilèë. Choë jeuët geupeutamah bak plôk ehtisa.',
'tooltip-summary' => 'Pasoë éhtisa paneuk',
+# Info page
+'pageinfo-toolboxlink' => 'Teuneurang laman',
+
# Browsing diffs
'previousdiff' => '← Bida away',
'nextdiff' => 'Geunantoë lheuëh nyan →',
'gotaccount' => "Du hast bereits ein Benutzerkonto? '''$1'''.",
'gotaccountlink' => 'Anmelden',
'userlogin-resetlink' => 'Die Anmeldedaten vergessen?',
-'userlogin-resetpassword-link' => 'Passwort zurücksetzen',
+'userlogin-resetpassword-link' => 'Passwort vergessen?',
'helplogin-url' => 'Help:Anmelden',
'userlogin-helplink' => '[[{{MediaWiki:helplogin-url}}|Hilfe beim Anmelden]]',
'userlogin-loggedin' => 'Du bist bereits als {{GENDER:$1|$1}} angemeldet.
* @author AK
* @author Aitolos
* @author Assassingr
+ * @author Astralnet
* @author Azimout
* @author Badseed
* @author Chomwitt
'version-license' => 'Άδεια χρήσης',
'version-poweredby-credits' => "Αυτό το wiki λειτουργεί με το λογισμικό '''[//www.mediawiki.org/ MediaWiki]''', πνευματική ιδιοκτησία © 2001-$1 $2.",
'version-poweredby-others' => 'άλλοι',
+'version-poweredby-translators' => 'translatewiki.net μεταφραστές',
'version-credits-summary' => 'Θα θέλαμε να αναγνωρίσουμε τη συμβολή των παρακάτω προσώπων στο [[Special:Version|MediaWiki]].',
'version-license-info' => "Το MediaWiki είναι ελεύθερο λογισμικό. Μπορείτε να το αναδιανείμετε ή/και να το τροποποιήσετε υπό τους όρους της άδειας GNU General Public License όπως αυτή εκδόθηκε από το Free Software Foundation· είτε της δεύτερης έκδοσης της άδειας, είτε (κατ' επιλογή σας) οποιασδήποτε επόμενης έκδοσης.
'tags-display-header' => 'Εμφάνιση στις λίστες αλλαγής',
'tags-description-header' => 'Πλήρης περιγραφή του νοήματος',
'tags-hitcount-header' => 'Αλλαγές με ετικέτα',
+'tags-active-yes' => 'Ναι',
+'tags-active-no' => 'Όχι',
'tags-edit' => 'επεξεργασία',
'tags-hitcount' => '$1 {{PLURAL:$1|αλλαγή|αλλαγές}}',
'mailerror' => 'Error sending mail: $1',
'acct_creation_throttle_hit' => 'Visitors to this wiki using your IP address have created {{PLURAL:$1|1 account|$1 accounts}} in the last day, which is the maximum allowed in this time period.
As a result, visitors using this IP address cannot create any more accounts at the moment.',
-'emailauthenticated' => 'Your email address was authenticated on $2 at $3.',
-'emailnotauthenticated' => 'Your email address is not yet authenticated.
+'emailauthenticated' => 'Your email address was confirmed on $2 at $3.',
+'emailnotauthenticated' => 'Your email address is not yet confirmed.
No email will be sent for any of the following features.',
'noemailprefs' => 'Specify an email address in your preferences for these features to work.',
'emailconfirmlink' => 'Confirm your email address',
'subject' => 'Izenburua:',
'minoredit' => 'Hau aldaketa txikia da',
'watchthis' => 'Orrialde hau jarraitu',
-'savearticle' => 'Gorde orrialdea',
+'savearticle' => 'Gorde orria',
'preview' => 'Aurrebista erakutsi',
'showpreview' => 'Aurrebista erakutsi',
'showlivepreview' => 'Zuzeneko aurrebista',
# Special:UploadStash
'uploadstash' => 'انبار بارگذاری',
'uploadstash-summary' => 'این صفحه دسترسی به پروندههایی که بارگذاری شدهاند (یا در حال بارگذاری هستند) اما هنوز در ویکی منتشر نشدهاند را فراهم میکند. این پروندهها توسط هیچ کاربری به جز کسی که آنها را بارگذاری کرده قابل دیدن نیستند.',
-'uploadstash-clear' => 'پاک کردن پروندههای انبارشده',
+'uploadstash-clear' => 'پاککردن پروندههای انبارشده',
'uploadstash-nofiles' => 'شما هیچ پروندهٔ انبارشدهای ندارید.',
'uploadstash-badtoken' => 'انجام این اقدام ناموفق بود، احتمالاً به این دلیل که اعتبار ویرایش شما به اتمام رسیده است. دوباره امتحان کنید.',
-'uploadstash-errclear' => 'پاک کردن پروندهها ناموفق بود.',
+'uploadstash-errclear' => 'پاککردن پروندهها ناموفق بود.',
'uploadstash-refresh' => 'تازهکردن فهرست پروندهها',
'invalid-chunk-offset' => 'جابجایی نامعتبر قطعه',
'ipbreason' => 'دلیل:',
'ipbreasonotherlist' => 'دلیل دیگر',
'ipbreason-dropdown' => '*دلایل متداول قطع دسترسی
-**وارد کردن اطلاعات نادرست
-**پاک کردن اطلاعات مفید از صفحهها
+**واردکردن اطلاعات نادرست
+**پاککردن اطلاعات مفید از صفحهها
**هرزنگاری از طریق درج مکرر پیوند به وبگاهها
**درج چرندیات یا نوشتههای بیمعنا در صفحهها
**تهدید یا ارعاب دیگر کاربران
# action=purge
'confirm_purge_button' => 'تأیید',
-'confirm-purge-top' => 'پاک کردن نسخهٔ حافظهٔ نهانی (Cache) این صفحه را تأیید میکنید؟',
+'confirm-purge-top' => 'پاککردن نسخهٔ حافظهٔ نهانی (Cache) این صفحه را تأیید میکنید؟',
'confirm-purge-bottom' => 'خالی کردن میانگیر یک صفحه باعث میشود که آخرین نسخهٔ آن نمایش یابد.',
# action=watch/unwatch
'gotaccount' => "Jos sinulla on jo tunnus, voit '''$1'''.",
'gotaccountlink' => 'kirjautua sisään',
'userlogin-resetlink' => 'Unohditko salasanasi?',
-'userlogin-resetpassword-link' => 'Vaihda salasanaasi',
+'userlogin-resetpassword-link' => 'Unohditko salasanasi?',
'helplogin-url' => 'Help:Sisäänkirjautuminen',
'userlogin-helplink' => '[[{{MediaWiki:helplogin-url}}|Auta sisäänkirjautumisessa]]',
'userlogin-loggedin' => 'Olet jo kirjautunut sisään tunnuksella {{GENDER:$1|$1}}.
'randompage-nopages' => '个只名字空间冇𠮶页面。',
# Random redirect
-'randomredirect' => '随机重定向页面',
+'randomredirect' => '随机重定向',
'randomredirect-nopages' => '个只名字空间冇重定向页面。',
# Statistics
'linkshere' => '下底𠮶页面链接到[[:$1]]:',
'nolinkshere' => '冇页面链接到[[:$1]]。',
'nolinkshere-ns' => '选正𠮶空间名内冇页面链接到[[:$1]]。',
-'isredirect' => '重定向页',
+'isredirect' => '重定向页面',
'istemplate' => '含到',
'isimage' => '档案连结',
'whatlinkshere-prev' => '先$1只',
'tooltip-search' => '{{SITENAME}} sod',
'tooltip-search-go' => 'Hea just nanvachem pan asa zalear tea panar voch',
'tooltip-search-fulltext' => 'Hea utarea khatir pana sod',
-'tooltip-p-logo' => 'Mukhel panal bhett di',
+'tooltip-p-logo' => 'Mukhel panak bhett di',
'tooltip-n-mainpage' => 'Mukhel panak bhett di',
'tooltip-n-mainpage-description' => 'Mukhel Panak bhett di',
'tooltip-n-portal' => 'Hea prokolpa vixim, tumchean kitem korum ieta, khoim kitem sodchem',
* @author Jetlag
* @author Mnemonic kek
* @author Urhixidur
+ * @author Xiaomingyan
*/
$messages = array(
'file-info-size' => '$1 × $2像素,文件大小:$3,MIME類型:$4',
'file-nohires' => '無做得提供嘅還較高分辨率。',
'svg-long-desc' => 'SVG文件,尺寸:$1×$2像素,文件大細:$3',
-'show-big-image' => '完全分辨率',
+'show-big-image' => '完整分辨率',
# Special:NewFiles
'newimages' => 'Sîn-kien thù-chhiong ke va̍k-lòng',
'acct_creation_throttle_hit' => 'מבקרים באתר זה דרך כתובת ה־IP שלכם כבר יצרו {{PLURAL:$1|חשבון אחד|$1 חשבונות}} ביום האחרון. זהו המקסימום המותר בתקופה זו.
לפיכך, מבקרים דרך כתובת ה־IP הזו לא יכולים ליצור חשבונות נוספים ברגע זה.',
'emailauthenticated' => 'כתובת הדוא"ל שלך אומתה ב־$3, $2.',
-'emailnotauthenticated' => '×\9bת×\95×\91ת ×\94×\93×\95×\90"×\9c ש×\9c×\9b×\9d ×¢×\93×\99×\99×\9f ×\9c×\90 ×\90×\95שרה.
+'emailnotauthenticated' => '×\9bת×\95×\91ת ×\94×\93×\95×\90"×\9c ש×\9c×\9b×\9d ×¢×\93×\99×\99×\9f ×\9c×\90 ×\90×\95×\9eתה.
לא יישלח אליכם דוא"ל עבור אף אחת מהאפשרויות הבאות.',
'noemailprefs' => 'אנא ציינו כתובת דוא"ל בהעדפות שלכם כדי שתכונות אלה יעבדו.',
'emailconfirmlink' => 'אישור כתובת הדוא"ל שלך',
* $3 - time',
'emailnotauthenticated' => 'Message in [[Special:Preferences]] > {{int:prefs-personal}} > {{int:email}}.
-It appears after saving your email address but before it has been authenticated.',
+It appears after saving your email address but before you confirm it.',
'noemailprefs' => 'Message appearing in the "Email options" section of the "User profile" page in [[Special:Preferences|Preferences]], when no user email address has been entered.',
'emailconfirmlink' => 'Link to [[Special:ConfirmEmail]].
'exif-dc-publisher' => 'One or more publisher of resource.
{{Identical|Publisher}}',
'exif-dc-relation' => "Something related to this image. Often a list of URL's to related images.",
-'exif-dc-rights' => 'Copyright information about the image/media given in informal language.',
+'exif-dc-rights' => 'Copyright information about the image/media given in informal language.
+{{Identical|Right}}',
'exif-dc-source' => 'Source of the image. This is another image that this image is based on. This does not refer to the person who provided the image.',
'exif-dc-type' => 'Type or genre of image/media. This might be something like painting or photograph.',
'actionthrottledtext' => 'Kot ukrep proti smetju, je število izvajanj tega dejanja v časovnem obdobju omejeno, in vi ste ta limit presegli.
Prosimo, poskusite znova čez nekaj minut.',
'protectedpagetext' => 'Ta stran je bila zaklenjena za preprečitev urejanja ali drugih dejanj.',
-'viewsourcetext' => 'Lahko si ogledate in kopirate vsebino te strani:',
+'viewsourcetext' => 'Vsebino te strani si lahko ogledate in kopirate:',
'viewyourtext' => "Lahko si ogledate in kopirate vsebino '''vaših urejanj''' te strani:",
'protectedinterface' => 'Prikazana stran vsebuje besedilo vmesnika programja na tem wikiju in je zaradi preprečevanja zlorab zaščitena.
'userlogin-resetpassword-link' => 'Ponastavite svoje geslo',
'helplogin-url' => 'Help:Prijava',
'userlogin-helplink' => '[[{{MediaWiki:helplogin-url}}|Pomoč pri prijavi]]',
-'userlogin-loggedin' => 'Ste že prijavljeni kot {{GENDER:$1|$1}}.
+'userlogin-loggedin' => 'Prijavljeni ste že kot {{GENDER:$1|$1}}.
Uporabite spodnji obrazec, da se prijavite kot drug uporabnik.',
'userlogin-createanother' => 'Ustvari drug račun',
'createacct-join' => 'Spodaj vnesite svoje informacije.',
'summary-preview' => 'Predogled povzetka',
'subject-preview' => 'Predogled zadeve/naslova:',
'blockedtitle' => 'Uporabnik je blokiran',
-'blockedtext' => "'''Urejanje z vašim uporabniškim imenom oziroma IP-naslovom je bilo onemogočeno.'''
+'blockedtext' => "'''Urejanje z vašim uporabniškim imenom oziroma IP-naslovom je onemogočeno.'''
Blokiral vas je $1.
-Podan razlog je ''$2''.
+Podani razlog je ''$2''.
-* Začetek blokade: $8
-* Potek blokade: $6
-* Namen blokade: $7
+* začetek blokade: $8
+* potek blokade: $6
+* blokirani uporabnik: $7
-O blokiranju se lahko pogovorite z $1 ali katerim drugim [[{{MediaWiki:Grouppage-sysop}}|administratorjem]].
-Vedite, da lahko ukaz »Pošlji uporabniku e-pismo« uporabite le, če ste v [[Special:Preferences|nastavitvah]] vpisali in potrdili svoj elektronski naslov ter le-ta ni bil blokiran.
+O blokiranju se lahko pogovorite z uporabnikom/-co $1 ali katerim drugim [[{{MediaWiki:Grouppage-sysop}}|administratorjem]].
+Vedite, da lahko ukaz »Pošlji uporabniku e-pismo« uporabite le, če ste v [[Special:Preferences|nastavitvah]] vpisali in potrdili svoj elektronski naslov in ta ni blokiran.
Vaš IP-naslov je $3, številka blokade pa #$5.
Prosimo, vključite ju v vse morebitne poizvedbe.",
'autoblockedtext' => "Vaš IP-naslov je bil samodejno blokiran, saj je bil uporabljen s strani drugega uporabnika, ki ga je blokiral $1.
# Account creation failure
'cantcreateaccounttitle' => 'Računa ni moč ustvariti',
-'cantcreateaccount-text' => "Registracija novega uporabnika iz tega IP-naslova ('''$1''') je bila blokirana s strani [[User:$3|$3]].
+'cantcreateaccount-text' => "Registracije z IP-naslova ('''$1''') je administrator(ka) [[User:$3|$3]] blokiral(a).
-Razlog, ki ga je podal $3, je ''$2''.",
+Razlog, ki ga je $3 podal(a), je ''$2''.",
# History pages
'viewpagelogs' => 'Poglej dnevniške zapise o strani',
'blocklog-showsuppresslog' => 'Ta uporabnik je že bil blokiran in skrit.
Dnevnik skrivanja je na voljo spodaj:',
'blocklogentry' => '[[$1]] blokiran s časom poteka blokade $2 $3',
-'reblock-logentry' => 'spremenil nastavitve blokade za [[$1]] z iztekom dne $2 ob $3',
+'reblock-logentry' => 'je spremenil(a) nastavitve blokade za [[$1]] na čas $2 $3',
'blocklogtext' => 'Prikazan je dnevnik blokiranja in deblokiranja uporabnikov. Samodejno blokirani IP-naslovi niso navedeni. Trenutno veljavna blokiranja so navedena na [[Special:BlockList|seznamu blokad]].',
'unblocklogentry' => 'je deblokiral(-a) »$1«',
'block-log-flags-anononly' => 'samo za brezimne uporabnike',
'deletepage' => 'Обриши страницу',
'confirm' => 'Потврди',
'excontent' => 'садржај је био: „$1“',
-'excontentauthor' => 'садржај је био: „$1“ (а једини уређивач је био „[[Special:Contributions/$2|$2]]“)',
+'excontentauthor' => 'садржај је био: „$1“ (а једини уредник је био „[[Special:Contributions/$2|$2]]“)',
'exbeforeblank' => 'садржај пре брисања је био: „$1“',
'exblank' => 'страница је била празна',
'delete-confirm' => 'Брисање странице „$1“',
'undeleteextrahelp' => "Да бисте вратили целу историју странице, оставите све кућице неозначене и кликните на дугме '''''{{int:undeletebtn}}'''''.
Ако желите да вратите одређене измене, означите их и кликните на '''''{{int:undeletebtn}}'''''.",
'undeleterevisions' => '$1 {{PLURAL:$1|измена је архивирана|измене су архивиране|измена је архивирано}}',
-'undeletehistory' => 'Ако вратите страницу, све измене ће бити враћене њеној историји.
-Ð\90ко Ñ\98е Ñ\83 меÑ\92Ñ\83вÑ\80еменÑ\83 напÑ\80авÑ\99ена нова Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81 иÑ\81Ñ\82им називом, вÑ\80аÑ\9bене измене Ñ\9bе Ñ\81е поÑ\98авиÑ\82и Ñ\83 Ñ\80аниÑ\98ом историји.',
+'undeletehistory' => 'Ако вратите страницу, све ревизије ће бити враћене њеној историји.
+Ð\90ко Ñ\98е Ñ\83 меÑ\92Ñ\83вÑ\80еменÑ\83 напÑ\80авÑ\99ена нова Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81 иÑ\81Ñ\82им називом, вÑ\80аÑ\9bене измене Ñ\9bе Ñ\81е поÑ\98авиÑ\82и Ñ\83 Ñ\9aеноÑ\98 Ñ\80аниÑ\98оÑ\98 историји.',
'undeleterevdel' => 'Враћање неће бити извршено ако је резултат тога делимично брисање последње измене.
У таквим случајевима морате искључити или открити најновије обрисане измене.',
'undeletehistorynoadmin' => 'Ова страница је обрисана.
'autosumm-blank' => 'Потпуно обрисана страница',
'autosumm-replace' => 'Замена садржаја странице са „$1“',
'autoredircomment' => 'Преусмерење на [[$1]]',
-'autosumm-new' => 'Ð\9dапÑ\80авÑ\99ена Ñ\81Ñ\82Ñ\80аниÑ\86а Ñ\81а: â\80\9e$1â\80\9c',
+'autosumm-new' => 'Ð\9dова Ñ\81Ñ\82Ñ\80аниÑ\86а: $1',
# Size units
'size-bytes' => '$1 B',
'linksearch-ok' => 'Pretraži',
'linksearch-text' => 'Mogu se koristiti džokeri poput „*.wikipedia.org“.<br />
Potreban je najviši domen, kao „*.org“.<br />
-Podržani protokoli: <code>$1</code> (zadaje http:// ako ne navedete protokol).',
+{{PLURAL:$2|Podržan protokol|Podržani protokoli}}: <code>$1</code> (zadaje http:// ako ne navedete protokol).',
'linksearch-line' => '$1 veza u $2',
'linksearch-error' => 'Džokeri se mogu pojaviti samo na početku adrese.',
'deletepage' => 'Obriši stranicu',
'confirm' => 'Potvrdi',
'excontent' => 'sadržaj je bio: „$1“',
-'excontentauthor' => 'sadržaj je bio: „$1“ (a jedini uređivač je bio „[[Special:Contributions/$2|$2]]“)',
+'excontentauthor' => 'sadržaj je bio: „$1“ (a jedini urednik je bio „[[Special:Contributions/$2|$2]]“)',
'exbeforeblank' => 'sadržaj pre brisanja je bio: „$1“',
'exblank' => 'stranica je bila prazna',
'delete-confirm' => 'Brisanje stranice „$1“',
'undeleteextrahelp' => "Da biste vratili celu istoriju stranice, ostavite sve kućice neoznačene i kliknite na dugme '''''{{int:undeletebtn}}'''''.
Ako želite da vratite određene izmene, označite ih i kliknite na '''''{{int:undeletebtn}}'''''.",
'undeleterevisions' => '$1 {{PLURAL:$1|izmena je arhivirana|izmene su arhivirane|izmena je arhivirano}}',
-'undeletehistory' => 'Ako vratite stranicu, sve izmene će biti vraćene njenoj istoriji.
-Ako je u međuvremenu napravljena nova stranica s istim nazivom, vraćene izmene će se pojaviti u ranijom istoriji.',
+'undeletehistory' => 'Ako vratite stranicu, sve revizije će biti vraćene njenoj istoriji.
+Ako je u međuvremenu napravljena nova stranica s istim nazivom, vraćene izmene će se pojaviti u njenoj ranijoj istoriji.',
'undeleterevdel' => 'Vraćanje neće biti izvršeno ako je rezultat toga delimično brisanje poslednje izmene.
U takvim slučajevima morate isključiti ili otkriti najnovije obrisane izmene.',
'undeletehistorynoadmin' => 'Ova stranica je obrisana.
'autosumm-blank' => 'Potpuno obrisana stranica',
'autosumm-replace' => 'Zamena sadržaja stranice sa „$1“',
'autoredircomment' => 'Preusmerenje na [[$1]]',
-'autosumm-new' => 'Napravljena stranica sa: „$1“',
+'autosumm-new' => 'Nova stranica: $1',
# Size units
'size-bytes' => '$1 B',
'logentry-move-move-noredirect' => '$1 je {{GENDER:$2|premestio|premestila}} stranicu $3 na $4 bez ostavljanja preusmerenja',
'logentry-move-move_redir' => '$1 je {{GENDER:$2|premestio|premestila}} stranicu $3 na $4 preko preusmerenja',
'logentry-move-move_redir-noredirect' => '$1 je {{GENDER:|premestio|premestila}} stranicu $3 na $4 preko preusmerenja bez ostavljanja preusmerenja',
-'logentry-patrol-patrol' => '$1 je {{GENDER:$2|osznačio|označila}} izenu $4 stranice $3 kao patroliranu',
+'logentry-patrol-patrol' => '$1 je {{GENDER:$2|označio|označila}} izmenu $4 stranice $3 kao patroliranu',
'logentry-patrol-patrol-auto' => '$1 je automatski {{GENDER:$2|označio|označila}} izmenu $4 stranice $3 kao pregledanu',
'logentry-newusers-newusers' => '$1 je {{GENDER:$2|otvorio|otvorila}} korisnički nalog',
'logentry-newusers-create' => '$1 je {{GENDER:$2|otvorio|otvorila}} korisnički nalog',
'gotaccount' => 'Zaten bir hesabınız var mı? $1.',
'gotaccountlink' => 'Oturum açın',
'userlogin-resetlink' => 'Giriş bilgilerinizi mi unuttunuz?',
-'userlogin-resetpassword-link' => 'Parolanızı sıfırlayın',
+'userlogin-resetpassword-link' => 'Parolanızı mı unuttunuz?',
'helplogin-url' => 'Help:Oturum açma',
'userlogin-helplink' => '[[{{MediaWiki:helplogin-url}}|Oturum açma konusunda yardım alın]]',
'createacct-join' => 'Aşağıya bilgilerinizi girin.',
'userlogin-resetpassword-link' => '重置你的密码',
'helplogin-url' => 'Help:登录',
'userlogin-helplink' => '[[{{MediaWiki:helplogin-url}}|登录帮助]]',
-'userlogin-loggedin' => '您已经作为{{GENDER:$1|$1}}登录。
-使用以下表单以作为另一账户登录。',
-'userlogin-createanother' => '创建另一个帐户',
+'userlogin-loggedin' => '你已经以{{GENDER:$1|$1}}的身份登录。使用下面的表格以其他用户的身份登录。',
+'userlogin-createanother' => '创建另一个账户',
'createacct-join' => '请在下面输入你的信息。',
'createacct-another-join' => '在下方输入新帐户信息。',
'createacct-emailrequired' => '电子邮件地址',
'createacct-realname' => '真实姓名 (可选)',
'createaccountreason' => '原因:',
'createacct-reason' => '原因',
-'createacct-reason-ph' => '为ä»\80ä¹\88æ\82¨è¦\81å\88\9b建å\8f¦ä¸\80个å¸\90户',
+'createacct-reason-ph' => 'ä½ ä¸ºä»\80ä¹\88è¦\81å\88\9b建å\8f¦ä¸\80个账户',
'createacct-captcha' => '安全检查',
'createacct-imgcaptcha-ph' => '请输入上图中的文字',
'createacct-submit' => '创建您的账户',
-'createacct-another-submit' => '创建另一个帐户',
+'createacct-another-submit' => '创建另一个账户',
'createacct-benefit-heading' => '{{SITENAME}}是由像您这样的人建立的。',
'createacct-benefit-body1' => '{{PLURAL:$1|编辑}}',
'createacct-benefit-body2' => '{{PLURAL:$1|页面}}',
# Special:ChangeEmail
'changeemail' => '更改电子邮件地址',
-'changeemail-header' => '更改帐户的电子邮件地址',
-'changeemail-text' => 'å¡«å\86\99æ¤è¡¨å\8d\95å\8f¯ä»¥æ\9b´æ\94¹æ\82¨ç\9a\84ç\94µå\90é\82®ä»¶å\9c°å\9d\80ã\80\82æ\82¨å°\86é\9c\80è¦\81è¾\93å\85¥æ\82¨ç\9a\84å¯\86ç \81以确认æ¤更改。',
+'changeemail-header' => '更改账户电子邮件地址',
+'changeemail-text' => 'å®\8cæ\88\90è¯¥è¡¨æ ¼ä»¥æ\9b´æ\94¹ä½ ç\9a\84ç\94µå\90é\82®ä»¶å\9c°å\9d\80ã\80\82ä½ é\9c\80è¦\81è¾\93å\85¥ä½ ç\9a\84å¯\86ç \81以确认该更改。',
'changeemail-no-info' => '
您必须登录以直接访问本页。',
'changeemail-oldemail' => '当前电子邮件地址:',
# Unused templates
'unusedtemplates' => '未使用模板',
-'unusedtemplatestext' => 'æ¤é¡µé\9d¢å\88\97å\87º{{ns:template}}å\90\8då\97空é\97´ä¸\8bæ\89\80æ\9c\89æ\9cªè¢«å\85¶å®\83页é\9d¢ä½¿ç\94¨ç\9a\84页é\9d¢ã\80\82请å\9c¨å\88 é\99¤è¿\99äº\9b模æ\9d¿å\89\8dæ£\80æ\9f¥å\85¶å®\83é\93¾å\85¥è¯¥æ¨¡æ\9d¿ç\9a\84页é\9d¢。',
+'unusedtemplatestext' => 'æ\9c¬é¡µé\9d¢å\88\97å\87º{{ns:template}}å\90\8då\97空é\97´ä¸æ\89\80æ\9c\89æ\9cªå\8c\85å\90«äº\8eå\85¶å®\83页é\9d¢ç\9a\84页é\9d¢ã\80\82请记å¾\97å\9c¨å\88 é\99¤è¿\99äº\9b模æ\9d¿å\89\8dæ£\80æ\9f¥å\85¶ä»\96é\93¾è\87³å®\83们ç\9a\84é\93¾æ\8e¥。',
'unusedtemplateswlh' => '其它链接',
# Random page
'statistics-edits-average' => '每页平均编辑数',
'statistics-views-total' => '查看总数',
'statistics-views-total-desc' => '不存在页面和特殊页面的查看数未计入',
-'statistics-views-peredit' => '每次编辑查看数',
+'statistics-views-peredit' => '每编辑查看数',
'statistics-users' => '注册[[Special:ListUsers|用户]]',
'statistics-users-active' => '活跃用户',
'statistics-users-active-desc' => '在前$1天中操作过的用户',
'pageswithprop' => '有页面属性的页面',
'pageswithprop-legend' => '有页面属性的页面',
-'pageswithprop-text' => 'æ¤é¡µé\9d¢å\88\97å\87ºäº\86使ç\94¨ç\89¹å®\9a页é\9d¢å±\9eæ\80§ç\9a\84页é\9d¢å\90\8då\8d\95。',
+'pageswithprop-text' => 'æ\9c¬é¡µé\9d¢å\88\97å\87ºä½¿ç\94¨ç\89¹å®\9a页é\9d¢å±\9eæ\80§ç\9a\84页é\9d¢。',
'pageswithprop-prop' => '属性名称:',
'pageswithprop-submit' => '提交',
'pageswithprop-prophidden-long' => '长文本属性值已隐藏($1)',
'pageswithprop-prophidden-binary' => '已隐藏二进制属性值($1)',
'doubleredirects' => '双重重定向',
-'doubleredirectstext' => '本页面列出重定向至其他重定向页的页面。每行含有第一及第二重定向的链接和第二重定向的目标(通常是第一重定向应该指向的“真实”目标页面)。<del>带删除线的</del>条目已被解决。',
+'doubleredirectstext' => '本页面列出重定向至其他重定向页面的页面。每行含有第一及第二重定向的链接和第二重定向的目标(这通常是第一重定向应该指向的“实际”目标页面)。<del>带删除线的</del>条目已经被解决。',
'double-redirect-fixed-move' => '[[$1]]已被移动。它现在重定向至[[$2]]。',
'double-redirect-fixed-maintenance' => '修复双重重定向自[[$1]]至[[$2]]。',
-'double-redirect-fixer' => '重定向页修复器',
+'double-redirect-fixer' => '重定向修复器',
'brokenredirects' => '受损重定向',
-'brokenredirectstext' => '以下的重定向页面指向的是不存在的页面:',
+'brokenredirectstext' => '以下重定向链接至不存在的页面:',
'brokenredirects-edit' => '编辑',
'brokenredirects-delete' => '删除',
'wantedpages' => '需要的页面',
'wantedpages-badtitle' => '在结果组上的无效标题:$1',
'wantedfiles' => '需要的文件',
-'wantedfiletext-cat' => 'ä¸\8bå\88\97被使ç\94¨ç\9a\84æ\96\87件并ä¸\8då\98å\9c¨ã\80\82å·²å\88\97å\87ºå\8f¯è\83½å\98å\9c¨å¤\96é\83¨åª\92ä½\93åº\93ä¸ç\9a\84æ\96\87件ã\80\82ä»»ä½\95æ¤ç±»è¯¯æ\8a¥å°\86被<del>å\89\94é\99¤</del>ã\80\82æ¤å¤\96ï¼\8c[[:$1]]å\88\97å\87ºå\88\97å\87ºäº\86åµ\8cå\85¥ä¸\8då\98å\9c¨æ\96\87件ç\9a\84页é\9d¢。',
-'wantedfiletext-nocat' => 'ä¸\8bå\88\97被使ç\94¨ç\9a\84æ\96\87件并ä¸\8då\98å\9c¨ã\80\82å·²å\88\97å\87ºå\8f¯è\83½å\98å\9c¨å¤\96é\83¨åª\92ä½\93åº\93ä¸ç\9a\84æ\96\87件ã\80\82ä»»ä½\95æ¤ç±»è¯¯æ\8a¥å°\86被<del>å\89\94é\99¤</del>。',
+'wantedfiletext-cat' => '以ä¸\8bæ\96\87件被使ç\94¨ï¼\8cä½\86并ä¸\8då\98å\9c¨ã\80\82æ\9d¥è\87ªå¤\96é\83¨åº\93ç\9a\84æ\96\87件å\8d³ä½¿å\98å\9c¨ä¹\9få\8f¯è\83½è¢«å\88\97å\87ºã\80\82ä»»ä½\95è¿\99类误æ\8a¥ä¼\9aç\94¨<del>å\88 é\99¤çº¿</del>æ \87è®°ã\80\82å\8f¦å¤\96ï¼\8cæ\8f\92å\85¥ä¸\8då\98å\9c¨ç\9a\84æ\96\87件ç\9a\84页é\9d¢å\88\97äº\8e[[:$1]]。',
+'wantedfiletext-nocat' => '以ä¸\8bæ\96\87件被使ç\94¨ï¼\8cä½\86并ä¸\8då\98å\9c¨ã\80\82æ\9d¥è\87ªå¤\96é\83¨åº\93ç\9a\84æ\96\87件å\8d³ä½¿å\98å\9c¨ä¹\9få\8f¯è\83½è¢«å\88\97å\87ºã\80\82ä»»ä½\95è¿\99类误æ\8a¥ä¼\9aç\94¨<del>å\88 é\99¤çº¿</del>æ \87è®°。',
'wantedtemplates' => '需要的模板',
'mostlinked' => '最多链接页面',
'mostlinkedcategories' => '最多链接分类',
'mostrevisions' => '最多版本页面',
'prefixindex' => '所有有前缀的页面',
'prefixindex-namespace' => '所有有前缀的页面($1名字空间)',
-'prefixindex-strip' => '在列表中省略前缀',
+'prefixindex-strip' => '在列表中除去前缀',
'shortpages' => '短页面',
'longpages' => '长页面',
'deadendpages' => '断链页面',
'ancientpages' => '最老页面',
'move' => '移动',
'movethispage' => '移动本页',
-'unusedimagestext' => '下列文件已存在,但并未插入任何页面。
-请注意其它网站可能会直接通过URL链接此文件,因此下面列出的文件依然有可能被使用。',
+'unusedimagestext' => '以下文件实际存在,但并没有插入任何页面。请注意,其他网站可能会使用直接URL链接某个文件,因此它即使被实际使用也可能在这里列出。',
'unusedcategoriestext' => '以下分类页面实际存在,即使没有其它页面或分类利用它们。',
'notargettitle' => '无目标',
'notargettext' => '您还没有指定一个目标页面或用户以进行此项操作。',
'alphaindexline' => '$1到$2',
'nextpage' => '下一页($1)',
'prevpage' => '上一页($1)',
-'allpagesfrom' => '显示从此处开始的页面:',
-'allpagesto' => '显示从此处结束的页面:',
+'allpagesfrom' => '显示页面开始于:',
+'allpagesto' => '显示页面结束于:',
'allarticles' => '所有页面',
'allinnamespace' => '所有页面($1名字空间)',
'allnotinnamespace' => '所有页面(非$1名字空间)',
'allpagesprev' => '前',
'allpagesnext' => '后',
'allpagessubmit' => '提交',
-'allpagesprefix' => '显示具有此前缀(名字空间)的页面:',
+'allpagesprefix' => '显示有该前缀的页面:',
'allpagesbadtitle' => '给定的页面标题是非法的,或者具有一个内部语言或内部 wiki 的前缀。它可能包含一个或更多的不能用于标题的字符。',
'allpages-bad-ns' => '在{{SITENAME}}中没有一个叫做"$1"的名字空间。',
-'allpages-hide-redirects' => '隐藏重定向页',
+'allpages-hide-redirects' => '隐藏重定向',
# SpecialCachedPage
'cachedspecial-viewing-cached-ttl' => '你正在查看本页面至少$1前的缓存版本。',
# Special:Categories
'categories' => '分类',
-'categoriespagetext' => '以下的{{PLURAL:$1|分类}}中包含了页面或媒体。
-[[Special:UnusedCategories|未用分类]]不会在这里列示。
-请同时参阅[[Special:WantedCategories|需要的分类]]。',
-'categoriesfrom' => '显示由此项起之分类:',
+'categoriespagetext' => '以下{{PLURAL:$1|分类包含}}页面或媒体文件。[[Special:UnusedCategories|未使用分类]]不显示在这里。另请见[[Special:WantedCategories|需要的分类]]。',
+'categoriesfrom' => '显示分类开始于:',
'special-categories-sort-count' => '按数量排列',
'special-categories-sort-abc' => '按字母排列',
'pageinfo-length' => '页面长度(字节)',
'pageinfo-article-id' => '页面ID',
'pageinfo-language' => '页面内容语言',
-'pageinfo-robot-policy' => '机器人索引',
+'pageinfo-robot-policy' => '爬虫索引',
'pageinfo-robot-index' => '允许',
'pageinfo-robot-noindex' => '不允许',
'pageinfo-views' => '查看数',
'pageinfo-watchers' => '页面监视者数',
'pageinfo-few-watchers' => '少于$1个监视者',
-'pageinfo-redirects-name' => '重定向到此页的数量',
-'pageinfo-subpages-name' => '本页子页面数',
+'pageinfo-redirects-name' => '至该页面的重定向数',
+'pageinfo-subpages-name' => '该页面的子页面数',
'pageinfo-subpages-value' => '$1($2个重定向页,$3个非重定向页)',
'pageinfo-firstuser' => '页面创建者',
'pageinfo-firsttime' => '页面创建日期',
'svg-long-desc' => 'SVG文件,尺寸为$1 × $2像素,文件大小:$3',
'svg-long-desc-animated' => '动画SVG文件,尺寸为$1 × $2像素,文件大小:$3',
'svg-long-error' => '无效的SVG文件:$1',
-'show-big-image' => '完全分辨率',
+'show-big-image' => '完整分辨率',
'show-big-image-preview' => '本预览的尺寸:$1。',
'show-big-image-other' => '其他{{PLURAL:$2|分辨率}}:$1。',
'show-big-image-size' => '$1×$2像素',
'allpagesprev' => '前',
'allpagesnext' => '後',
'allpagessubmit' => '提交',
-'allpagesprefix' => '顯示具有此前綴(名字空間)的頁面:',
+'allpagesprefix' => '顯示有此前綴的頁面:',
'allpagesbadtitle' => '給定的頁面標題是非法的,或者具有一個內部語言或內部 wiki 的前綴。它可能包含一個或更多的不能用於標題的字元。',
'allpages-bad-ns' => '在{{SITENAME}}中沒有一個叫做「$1」的名字空間。',
'allpages-hide-redirects' => '隱藏重定向頁',
$i = 0;
foreach ( $iterator as $file ) {
// Absolute sanity check for stashed files and file segments
- if ( !preg_match( '#(^\d{14}!|\.\d+\.\w+\.\d+$)#', basename( $file ) ) ) {
+ $base = basename( $file );
+ // @TODO: why are there thumbnails stored in here?
+ if ( !preg_match( '#(^\d{14}!|\.\d+\.\w+\.\d+$|-\w{12}\.\w{6}\.\d+\.)#', $base ) ) {
$this->output( "Skipped non-stash $file\n" );
continue;
}
* @class mw.Map
*
* @constructor
- * @param {boolean} [global=false] Whether to store the values in the global window
- * object or a exclusively in the object property 'values'.
+ * @param {Object|boolean} [values] Value-bearing object to map, or boolean
+ * true to map over the global object. Defaults to an empty object.
*/
- function Map( global ) {
- this.values = global === true ? window : {};
+ function Map( values ) {
+ this.values = values === true ? window : ( values || {} );
return this;
}
</p>
!!end
+!! test
+Don't break link parsing if language converter markup is in the caption.
+!! options
+language=sr variant=sr-ec
+!! input
+[[Main Page|-{R|main page}-]]
+!! result
+<p><a href="/wiki/Main_Page" title="Маин Паге">main page</a>
+</p>
+!! end
+
+# This test is currently broken in the PHP parser (bug 52661)
+!! test
+Don't break image parsing if language converter markup is in the caption.
+!! options
+language=sr
+disabled
+!! input
+[[File:Foobar.jpg|-{R|caption}-]]
+!! result
+<p><a href="/wiki/File:Foobar.jpg" class="image" title="caption"><img alt="caption" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a>
+</p>
+!! end
+
+# This test is currently broken in the PHP parser (bug 52661)
+!! test
+Don't break list handling if language converter markup is in the item.
+!! options
+language=zh variant=zh-cn
+disabled
+!! input
+;-{zh-cn:AAA;zh-tw:BBB}-
+!! result
+<dl><dt>AAA
+</dt></dl>
+
+!! end
+
+# This test is currently broken in the PHP parser (bug 52661)
+!! test
+Don't break table handling if language converter markup is in the cell.
+!! options
+language=sr variant=sr-ec
+disabled
+!! input
+{|
+|-
+| -{R|B}-
+|}
+!! result
+<table>
+
+<tr>
+<td> B
+</td></tr></table>
+
+!! end
+
!! test
Bug 529: Uncovered bullet
!! input
global $wgDBprefix;
$tables = $db->listTables( $wgDBprefix, __METHOD__ );
+
+ if ( $db->getType() === 'mysql' ) {
+ # bug 43571: cannot clone VIEWs under MySQL
+ $views = $db->listViews( $wgDBprefix, __METHOD__ );
+ $tables = array_diff( $tables, $views );
+ }
$tables = array_map( array( __CLASS__, 'unprefixTable' ), $tables );
// Don't duplicate test tables from the previous fataled run
* @covers Title::getParentCategories
*/
public function testTemplateCategories() {
- $title = Title::newFromText( "Categorized from template" );
- $page = WikiPage::factory( $title );
$user = new User();
- $user->mRights = array( 'createpage', 'edit', 'purge' );
+ $user->mRights = array( 'createpage', 'edit', 'purge', 'delete' );
+ $title = Title::newFromText( "Categorized from template" );
+ $page = WikiPage::factory( $title );
$page->doEditContent(
new WikitextContent( '{{Categorising template}}' ),
'Create a page with a template',
);
$this->assertEquals(
- array()
- , $title->getParentCategories()
+ array(),
+ $title->getParentCategories(),
+ 'Verify that the category doesn\'t contain the page before the template is created'
);
+ // Create template
$template = WikiPage::factory( Title::newFromText( 'Template:Categorising template' ) );
-
$template->doEditContent(
new WikitextContent( '[[Category:Solved bugs]]' ),
'Add a category through a template',
$jobs->loadParamsAndArgs( null, array( 'quiet' => true ), null );
$jobs->execute();
+ // Make sure page is in the category
$this->assertEquals(
- array( 'Category:Solved_bugs' => $title->getPrefixedText() )
- , $title->getParentCategories()
+ array( 'Category:Solved_bugs' => $title->getPrefixedText() ),
+ $title->getParentCategories(),
+ 'Verify that the page is in the category after the template is created'
+ );
+
+ // Edit the template
+ $template->doEditContent(
+ new WikitextContent( '[[Category:Solved bugs 2]]' ),
+ 'Change the category added by the template',
+ 0,
+ false,
+ $user
);
+
+ // Run the job queue
+ JobQueueGroup::destroySingletons();
+ $jobs = new RunJobs;
+ $jobs->loadParamsAndArgs( null, array( 'quiet' => true ), null );
+ $jobs->execute();
+
+ // Make sure page is in the right category
+ $this->assertEquals(
+ array( 'Category:Solved_bugs_2' => $title->getPrefixedText() ),
+ $title->getParentCategories(),
+ 'Verify that the page is in the right category after the template is edited'
+ );
+
+ // Now delete the template
+ $error = '';
+ $template->doDeleteArticleReal( 'Delete the template', false, 0, true, $error, $user );
+
+ // Run the job queue
+ JobQueueGroup::destroySingletons();
+ $jobs = new RunJobs;
+ $jobs->loadParamsAndArgs( null, array( 'quiet' => true ), null );
+ $jobs->execute();
+
+ // Make sure the page is no longer in the category
+ $this->assertEquals(
+ array(),
+ $title->getParentCategories(),
+ 'Verify that the page is no longer in the category after template deletion'
+ );
+
}
}
return json_decode( '"' . $str . '"' );
}
+ function getMockForViews() {
+ $db = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->setMethods( array( 'fetchRow', 'query' ) )
+ ->getMock();
+
+ $db->expects( $this->any() )
+ ->method( 'query' )
+ ->with( $this->anything() )
+ ->will(
+ $this->returnValue( null )
+ );
+
+ $db->expects( $this->any() )
+ ->method( 'fetchRow' )
+ ->with( $this->anything() )
+ ->will( $this->onConsecutiveCalls(
+ array( 'Tables_in_' => 'view1' ),
+ array( 'Tables_in_' => 'view2' ),
+ array( 'Tables_in_' => 'myview' ),
+ false # no more rows
+ ));
+ return $db;
+ }
+ /**
+ * @covers DatabaseMysqlBase::listViews
+ */
+ function testListviews() {
+ $db = $this->getMockForViews();
+
+ // The first call populate an internal cache of views
+ $this->assertEquals( array( 'view1', 'view2', 'myview'),
+ $db->listViews() );
+ $this->assertEquals( array( 'view1', 'view2', 'myview'),
+ $db->listViews() );
+
+ // Prefix filtering
+ $this->assertEquals( array( 'view1', 'view2' ),
+ $db->listViews( 'view' ) );
+ $this->assertEquals( array( 'myview' ),
+ $db->listViews( 'my' ) );
+ $this->assertEquals( array(),
+ $db->listViews( 'UNUSED_PREFIX' ) );
+ $this->assertEquals( array( 'view1', 'view2', 'myview'),
+ $db->listViews( '' ) );
+ }
+
+ /**
+ * @covers DatabaseMysqlBase::isView
+ * @dataProvider provideViewExistanceChecks
+ */
+ function testIsView( $isView, $viewName ) {
+ $db = $this->getMockForViews();
+
+ switch( $isView ) {
+ case true:
+ $this->assertTrue( $db->isView( $viewName ),
+ "$viewName should be considered a view" );
+ break;
+
+ case false:
+ $this->assertFalse( $db->isView( $viewName ),
+ "$viewName has not been defined as a view" );
+ break;
+ }
+
+ }
+
+ function provideViewExistanceChecks() {
+ return array(
+ // format: whether it is a view, view name
+ array( true, 'view1' ),
+ array( true, 'view2' ),
+ array( true, 'myview' ),
+
+ array( false, 'user' ),
+
+ array( false, 'view10' ),
+ array( false, 'my' ),
+ array( false, 'OH_MY_GOD' ), # they killed kenny!
+ );
+ }
+
}
assert.strictEqual( window.mw, window.mediaWiki, 'mw alias to mediaWiki' );
} );
- QUnit.test( 'mw.Map', 27, function ( assert ) {
+ QUnit.test( 'mw.Map', 28, function ( assert ) {
var arry, conf, funky, globalConf, nummy, someValues;
conf = new mw.Map();
'lorem': 'ipsum'
}, 'Map.get returns multiple values correctly as an object' );
+ assert.deepEqual( conf, new mw.Map( conf.values ), 'new mw.Map maps over existing values-bearing object' );
+
assert.deepEqual( conf.get( ['foo', 'notExist'] ), {
'foo': 'bar',
'notExist': null