Merge "Make MessageCache::load() require a language code"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 19 Oct 2016 01:38:43 +0000 (01:38 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 19 Oct 2016 01:38:43 +0000 (01:38 +0000)
170 files changed:
.travis.yml
RELEASE-NOTES-1.28
autoload.php
composer.json
includes/Defines.php
includes/EditPage.php
includes/MWGrants.php [new file with mode: 0644]
includes/MediaWiki.php
includes/MediaWikiServices.php
includes/MimeMagic.php
includes/OutputPage.php
includes/ServiceWiring.php
includes/api/ApiStashEdit.php
includes/api/i18n/de.json
includes/api/i18n/es.json
includes/api/i18n/fr.json
includes/api/i18n/gl.json
includes/api/i18n/he.json
includes/api/i18n/it.json
includes/api/i18n/ko.json
includes/api/i18n/lb.json
includes/api/i18n/mr.json
includes/api/i18n/pl.json
includes/api/i18n/pt.json
includes/api/i18n/sv.json
includes/api/i18n/zh-hans.json
includes/auth/AuthManager.php
includes/cache/MessageCache.php
includes/context/RequestContext.php
includes/deferred/LinksDeletionUpdate.php
includes/deferred/LinksUpdate.php
includes/diff/DifferenceEngine.php
includes/exception/MWExceptionHandler.php
includes/htmlform/fields/HTMLMultiSelectField.php
includes/installer/PostgresInstaller.php
includes/installer/i18n/lt.json
includes/jobqueue/JobQueueDB.php
includes/jobqueue/JobRunner.php
includes/jobqueue/jobs/AssembleUploadChunksJob.php
includes/jobqueue/jobs/PublishStashedFileJob.php
includes/libs/CryptHKDF.php [new file with mode: 0644]
includes/libs/IEContentAnalyzer.php [deleted file]
includes/libs/XmlTypeCheck.php [deleted file]
includes/libs/composer/ComposerJson.php
includes/libs/composer/ComposerLock.php
includes/libs/filebackend/FSFile.php [deleted file]
includes/libs/filebackend/FileBackend.php
includes/libs/filebackend/TempFSFile.php [deleted file]
includes/libs/filebackend/fsfile/FSFile.php [new file with mode: 0644]
includes/libs/filebackend/fsfile/TempFSFile.php [new file with mode: 0644]
includes/libs/iterators/IteratorDecorator.php [new file with mode: 0644]
includes/libs/iterators/NotRecursiveIterator.php [new file with mode: 0644]
includes/libs/mime/IEContentAnalyzer.php [new file with mode: 0644]
includes/libs/mime/MimeAnalyzer.php [new file with mode: 0644]
includes/libs/mime/XmlTypeCheck.php [new file with mode: 0644]
includes/libs/mime/defines.php [new file with mode: 0644]
includes/libs/mime/mime.info [new file with mode: 0644]
includes/libs/mime/mime.types [new file with mode: 0644]
includes/libs/objectcache/BagOStuff.php
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/DatabaseMysqlBase.php
includes/libs/rdbms/database/DatabaseMysqli.php
includes/libs/rdbms/database/DatabasePostgres.php
includes/libs/rdbms/database/DatabaseSqlite.php
includes/libs/rdbms/database/IDatabase.php
includes/libs/rdbms/lbfactory/LBFactory.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/libs/rdbms/loadbalancer/LoadBalancerSingle.php
includes/libs/rdbms/loadmonitor/LoadMonitor.php
includes/libs/xmp/XMP.php
includes/media/SVG.php
includes/mime.info [deleted file]
includes/mime.types [deleted file]
includes/parser/Parser.php
includes/parser/ParserOptions.php
includes/profiler/Profiler.php
includes/registration/ExtensionProcessor.php
includes/registration/ExtensionRegistry.php
includes/resourceloader/ResourceLoaderModule.php
includes/session/Session.php
includes/session/SessionBackend.php
includes/session/SessionManager.php
includes/specials/SpecialBooksources.php
includes/specials/SpecialMovepage.php
includes/user/User.php
includes/utils/BatchRowIterator.php
includes/utils/BatchRowUpdate.php
includes/utils/MWCryptHKDF.php
includes/utils/MWGrants.php [deleted file]
includes/utils/iterators/IteratorDecorator.php [deleted file]
includes/utils/iterators/NotRecursiveIterator.php [deleted file]
languages/i18n/ast.json
languages/i18n/be-tarask.json
languages/i18n/bn.json
languages/i18n/ca.json
languages/i18n/cdo.json
languages/i18n/crh-cyrl.json
languages/i18n/cs.json
languages/i18n/de.json
languages/i18n/diq.json
languages/i18n/en.json
languages/i18n/es.json
languages/i18n/et.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/gl.json
languages/i18n/hak.json
languages/i18n/he.json
languages/i18n/hr.json
languages/i18n/hu.json
languages/i18n/ia.json
languages/i18n/it.json
languages/i18n/ka.json
languages/i18n/kn.json
languages/i18n/ko.json
languages/i18n/lb.json
languages/i18n/lij.json
languages/i18n/lt.json
languages/i18n/lv.json
languages/i18n/mk.json
languages/i18n/mr.json
languages/i18n/nah.json
languages/i18n/nan.json
languages/i18n/nb.json
languages/i18n/ne.json
languages/i18n/nn.json
languages/i18n/pl.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ro.json
languages/i18n/ru.json
languages/i18n/sd.json
languages/i18n/sl.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/sv.json
languages/i18n/te.json
languages/i18n/tl.json
languages/i18n/uk.json
languages/i18n/yo.json
languages/i18n/zh-hans.json
maintenance/addRFCandPMIDInterwiki.php
maintenance/checkComposerLockUpToDate.php
maintenance/dev/includes/router.php
maintenance/doMaintenance.php
resources/src/mediawiki/htmlform/multiselect.js
resources/src/mediawiki/page/gallery.css
tests/parser/ParserTestRunner.php
tests/parser/fuzzTest.php
tests/phpunit/includes/MediaWikiServicesTest.php
tests/phpunit/includes/MimeMagicTest.php [deleted file]
tests/phpunit/includes/WatchedItemStoreUnitTest.php
tests/phpunit/includes/auth/AuthManagerTest.php
tests/phpunit/includes/auth/CheckBlocksSecondaryAuthenticationProviderTest.php
tests/phpunit/includes/auth/TemporaryPasswordPrimaryAuthenticationProviderTest.php
tests/phpunit/includes/changes/RecentChangeTest.php
tests/phpunit/includes/libs/composer/ComposerJsonTest.php
tests/phpunit/includes/libs/composer/ComposerLockTest.php
tests/phpunit/includes/libs/mime/MimeAnalyzerTest.php [new file with mode: 0644]
tests/phpunit/includes/page/WikiCategoryPageTest.php
tests/phpunit/includes/parser/ParserIntegrationTest.php
tests/phpunit/includes/session/PHPSessionHandlerTest.php
tests/phpunit/includes/session/SessionBackendTest.php
tests/phpunit/includes/session/SessionManagerTest.php
tests/phpunit/includes/session/TestUtils.php
tests/phpunit/includes/specialpage/SpecialPageFactoryTest.php
tests/phpunit/includes/specials/SpecialBooksourcesTest.php
tests/phpunit/includes/user/BotPasswordTest.php
tests/phpunit/suites/ParserTestTopLevelSuite.php

index 9062194..9738605 100644 (file)
@@ -55,7 +55,6 @@ notifications:
   email: false
   irc:
     channels:
-      - "chat.freenode.net#mediawiki-core"
       - "chat.freenode.net#mediawiki-feed"
     on_success: change
     on_failure: change
index b9278d0..75fc139 100644 (file)
@@ -227,8 +227,8 @@ changes to languages because of Phabricator reports.
   migrate to using the same functions on a ProxyLookup instance, obtainable from
   MediaWikiServices.
 * The ArticleAfterFetchContent, ArticleInsertComplete, ArticleSave, ArticleSaveComplete,
-  ArticleViewCustom, EditPageGetDiffText, EditPageGetPreviewText and ShowRawCssJs hooks
-  will now emit deprecation warnings if used.
+  ArticleViewCustom, EditFilterMerged, EditPageGetDiffText, EditPageGetPreviewText and
+  ShowRawCssJs hooks will now emit deprecation warnings if used.
 
 == Compatibility ==
 
index 748d954..3a2d06f 100644 (file)
@@ -296,6 +296,7 @@ $wgAutoloadLocalClasses = [
        'CreateAndPromote' => __DIR__ . '/maintenance/createAndPromote.php',
        'CreateFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/CreateFileOp.php',
        'CreditsAction' => __DIR__ . '/includes/actions/CreditsAction.php',
+       'CryptHKDF' => __DIR__ . '/includes/libs/CryptHKDF.php',
        'CryptRand' => __DIR__ . '/includes/libs/CryptRand.php',
        'CssContent' => __DIR__ . '/includes/content/CssContent.php',
        'CssContentHandler' => __DIR__ . '/includes/content/CssContentHandler.php',
@@ -435,7 +436,7 @@ $wgAutoloadLocalClasses = [
        'ExternalStoreHttp' => __DIR__ . '/includes/externalstore/ExternalStoreHttp.php',
        'ExternalStoreMedium' => __DIR__ . '/includes/externalstore/ExternalStoreMedium.php',
        'ExternalStoreMwstore' => __DIR__ . '/includes/externalstore/ExternalStoreMwstore.php',
-       'FSFile' => __DIR__ . '/includes/libs/filebackend/FSFile.php',
+       'FSFile' => __DIR__ . '/includes/libs/filebackend/fsfile/FSFile.php',
        'FSFileBackend' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
        'FSFileBackendDirList' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
        'FSFileBackendFileList' => __DIR__ . '/includes/libs/filebackend/FSFileBackend.php',
@@ -586,7 +587,7 @@ $wgAutoloadLocalClasses = [
        'IContextSource' => __DIR__ . '/includes/context/IContextSource.php',
        'IDBAccessObject' => __DIR__ . '/includes/dao/IDBAccessObject.php',
        'IDatabase' => __DIR__ . '/includes/libs/rdbms/database/IDatabase.php',
-       'IEContentAnalyzer' => __DIR__ . '/includes/libs/IEContentAnalyzer.php',
+       'IEContentAnalyzer' => __DIR__ . '/includes/libs/mime/IEContentAnalyzer.php',
        'IEUrlExtension' => __DIR__ . '/includes/libs/IEUrlExtension.php',
        'IExpiringStore' => __DIR__ . '/includes/libs/objectcache/IExpiringStore.php',
        'IJobSpecification' => __DIR__ . '/includes/jobqueue/JobSpecification.php',
@@ -631,7 +632,7 @@ $wgAutoloadLocalClasses = [
        'Interwiki' => __DIR__ . '/includes/interwiki/Interwiki.php',
        'InvalidPassword' => __DIR__ . '/includes/password/InvalidPassword.php',
        'InvalidateUserSesssions' => __DIR__ . '/maintenance/invalidateUserSessions.php',
-       'IteratorDecorator' => __DIR__ . '/includes/utils/iterators/IteratorDecorator.php',
+       'IteratorDecorator' => __DIR__ . '/includes/libs/iterators/IteratorDecorator.php',
        'IuConverter' => __DIR__ . '/languages/classes/LanguageIu.php',
        'JSCompilerContext' => __DIR__ . '/includes/libs/jsminplus.php',
        'JSMinPlus' => __DIR__ . '/includes/libs/jsminplus.php',
@@ -781,7 +782,7 @@ $wgAutoloadLocalClasses = [
        'MWExceptionHandler' => __DIR__ . '/includes/exception/MWExceptionHandler.php',
        'MWExceptionRenderer' => __DIR__ . '/includes/exception/MWExceptionRenderer.php',
        'MWFileProps' => __DIR__ . '/includes/utils/MWFileProps.php',
-       'MWGrants' => __DIR__ . '/includes/utils/MWGrants.php',
+       'MWGrants' => __DIR__ . '/includes/MWGrants.php',
        'MWHttpRequest' => __DIR__ . '/includes/http/MWHttpRequest.php',
        'MWLBFactory' => __DIR__ . '/includes/db/MWLBFactory.php',
        'MWMemcached' => __DIR__ . '/includes/compat/MemcachedClientCompat.php',
@@ -943,6 +944,7 @@ $wgAutoloadLocalClasses = [
        'MessageSpecifier' => __DIR__ . '/includes/libs/MessageSpecifier.php',
        'MigrateFileRepoLayout' => __DIR__ . '/maintenance/migrateFileRepoLayout.php',
        'MigrateUserGroup' => __DIR__ . '/maintenance/migrateUserGroup.php',
+       'MimeAnalyzer' => __DIR__ . '/includes/libs/mime/MimeAnalyzer.php',
        'MimeMagic' => __DIR__ . '/includes/MimeMagic.php',
        'MinifyScript' => __DIR__ . '/maintenance/minify.php',
        'MostcategoriesPage' => __DIR__ . '/includes/specials/SpecialMostcategories.php',
@@ -982,7 +984,7 @@ $wgAutoloadLocalClasses = [
        'NewPagesPager' => __DIR__ . '/includes/specials/pagers/NewPagesPager.php',
        'NewUsersLogFormatter' => __DIR__ . '/includes/logging/NewUsersLogFormatter.php',
        'NolinesImageGallery' => __DIR__ . '/includes/gallery/NolinesImageGallery.php',
-       'NotRecursiveIterator' => __DIR__ . '/includes/utils/iterators/NotRecursiveIterator.php',
+       'NotRecursiveIterator' => __DIR__ . '/includes/libs/iterators/NotRecursiveIterator.php',
        'NukeNS' => __DIR__ . '/maintenance/nukeNS.php',
        'NukePage' => __DIR__ . '/maintenance/nukePage.php',
        'NullFileJournal' => __DIR__ . '/includes/libs/filebackend/filejournal/NullFileJournal.php',
@@ -1413,7 +1415,7 @@ $wgAutoloadLocalClasses = [
        'TableDiffFormatter' => __DIR__ . '/includes/diff/TableDiffFormatter.php',
        'TablePager' => __DIR__ . '/includes/pager/TablePager.php',
        'TagLogFormatter' => __DIR__ . '/includes/logging/TagLogFormatter.php',
-       'TempFSFile' => __DIR__ . '/includes/libs/filebackend/TempFSFile.php',
+       'TempFSFile' => __DIR__ . '/includes/libs/filebackend/fsfile/TempFSFile.php',
        'TempFileRepo' => __DIR__ . '/includes/filerepo/FileRepo.php',
        'TemplateParser' => __DIR__ . '/includes/TemplateParser.php',
        'TemplatesOnThisPageFormatter' => __DIR__ . '/includes/TemplatesOnThisPageFormatter.php',
@@ -1580,7 +1582,7 @@ $wgAutoloadLocalClasses = [
        'XmlDumpWriter' => __DIR__ . '/includes/export/XmlDumpWriter.php',
        'XmlJsCode' => __DIR__ . '/includes/Xml.php',
        'XmlSelect' => __DIR__ . '/includes/XmlSelect.php',
-       'XmlTypeCheck' => __DIR__ . '/includes/libs/XmlTypeCheck.php',
+       'XmlTypeCheck' => __DIR__ . '/includes/libs/mime/XmlTypeCheck.php',
        'ZhConverter' => __DIR__ . '/languages/classes/LanguageZh.php',
        'ZipDirectoryReader' => __DIR__ . '/includes/utils/ZipDirectoryReader.php',
        'ZipDirectoryReaderError' => __DIR__ . '/includes/utils/ZipDirectoryReader.php',
index 884b64f..fdbd0cd 100644 (file)
@@ -40,7 +40,7 @@
                "wikimedia/relpath": "1.0.3",
                "wikimedia/running-stat": "1.1.0",
                "wikimedia/scoped-callback": "1.0.0",
-               "wikimedia/utfnormal": "1.0.3",
+               "wikimedia/utfnormal": "1.1.0",
                "wikimedia/wait-condition-loop": "1.0.1",
                "wikimedia/wrappedstring": "2.2.0",
                "zordius/lightncandy": "0.23"
index 02930ea..0616898 100644 (file)
@@ -97,32 +97,7 @@ define( 'CACHE_MEMCACHED', 2 );  // MemCached, must specify servers in $wgMemCac
 define( 'CACHE_ACCEL', 3 );      // APC, XCache or WinCache
 /**@}*/
 
-/**@{
- * Media types.
- * This defines constants for the value returned by File::getMediaType()
- */
-// unknown format
-define( 'MEDIATYPE_UNKNOWN', 'UNKNOWN' );
-// some bitmap image or image source (like psd, etc). Can't scale up.
-define( 'MEDIATYPE_BITMAP', 'BITMAP' );
-// some vector drawing (SVG, WMF, PS, ...) or image source (oo-draw, etc). Can scale up.
-define( 'MEDIATYPE_DRAWING', 'DRAWING' );
-// simple audio file (ogg, mp3, wav, midi, whatever)
-define( 'MEDIATYPE_AUDIO', 'AUDIO' );
-// simple video file (ogg, mpg, etc;
-// no not include formats here that may contain executable sections or scripts!)
-define( 'MEDIATYPE_VIDEO', 'VIDEO' );
-// Scriptable Multimedia (flash, advanced video container formats, etc)
-define( 'MEDIATYPE_MULTIMEDIA', 'MULTIMEDIA' );
-// Office Documents, Spreadsheets (office formats possibly containing apples, scripts, etc)
-define( 'MEDIATYPE_OFFICE', 'OFFICE' );
-// Plain text (possibly containing program code or scripts)
-define( 'MEDIATYPE_TEXT', 'TEXT' );
-// binary executable
-define( 'MEDIATYPE_EXECUTABLE', 'EXECUTABLE' );
-// archive file (zip, tar, etc)
-define( 'MEDIATYPE_ARCHIVE', 'ARCHIVE' );
-/**@}*/
+require_once __DIR__ . '/libs/mime/defines.php';
 
 /**@{
  * Antivirus result codes, for use in $wgAntivirusSetup.
index 8226da5..770a74e 100644 (file)
@@ -22,6 +22,7 @@
 
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
 
 /**
  * The edit page/HTML interface (split from Article)
@@ -1613,7 +1614,8 @@ class EditPage {
        protected function runPostMergeFilters( Content $content, Status $status, User $user ) {
                // Run old style post-section-merge edit filter
                if ( !ContentHandler::runLegacyHooks( 'EditFilterMerged',
-                       [ $this, $content, &$this->hookError, $this->summary ]
+                       [ $this, $content, &$this->hookError, $this->summary ],
+                       '1.21'
                ) ) {
                        # Error messages etc. could be handled within the hook...
                        $status->fatal( 'hookaborted' );
@@ -1639,7 +1641,7 @@ class EditPage {
                                // being set. This is used by ConfirmEdit to display a captcha
                                // without any error message cruft.
                        } else {
-                               $this->hookError = $status->getWikiText();
+                               $this->hookError = $this->formatStatusErrors( $status );
                        }
                        // Use the existing $status->value if the hook set it
                        if ( !$status->value ) {
@@ -1649,7 +1651,7 @@ class EditPage {
                } elseif ( !$status->isOK() ) {
                        # ...or the hook could be expecting us to produce an error
                        // FIXME this sucks, we should just use the Status object throughout
-                       $this->hookError = $status->getWikiText();
+                       $this->hookError = $this->formatStatusErrors( $status );
                        $status->fatal( 'hookaborted' );
                        $status->value = self::AS_HOOK_ERROR_EXPECTED;
                        return false;
@@ -1658,6 +1660,26 @@ class EditPage {
                return true;
        }
 
+       /**
+        * Wrap status errors in an errorbox for increased visiblity
+        *
+        * @param Status $status
+        * @return string
+        */
+       private function formatStatusErrors( Status $status ) {
+               $errmsg = $status->getHTML(
+                       'edit-error-short',
+                       'edit-error-long',
+                       $this->context->getLanguage()
+               );
+               return <<<ERROR
+<div class="errorbox">
+{$errmsg}
+</div>
+<br clear="all" />
+ERROR;
+       }
+
        /**
         * Return the summary to be used for a new section.
         *
@@ -2766,9 +2788,8 @@ class EditPage {
                $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'hiddencats' ],
                        Linker::formatHiddenCategories( $this->page->getHiddenCategories() ) ) );
 
-               if ( $this->mParserOutput ) {
-                       $wgOut->setLimitReportData( $this->mParserOutput->getLimitReportData() );
-               }
+               $wgOut->addHTML( Html::rawElement( 'div', [ 'class' => 'limitreport' ],
+                       self::getPreviewLimitReport( $this->mParserOutput ) ) );
 
                $wgOut->addModules( 'mediawiki.action.edit.collapsibleFooter' );
 
@@ -3546,12 +3567,47 @@ HTML
                        return '';
                }
 
-               return ResourceLoader::makeInlineScript(
-                       ResourceLoader::makeConfigSetScript(
-                               [ 'wgPageParseReport' => $output->getLimitReportData() ],
-                               true
-                       )
+               $limitReport = Html::rawElement( 'div', [ 'class' => 'mw-limitReportExplanation' ],
+                       wfMessage( 'limitreport-title' )->parseAsBlock()
                );
+
+               // Show/hide animation doesn't work correctly on a table, so wrap it in a div.
+               $limitReport .= Html::openElement( 'div', [ 'class' => 'preview-limit-report-wrapper' ] );
+
+               $limitReport .= Html::openElement( 'table', [
+                       'class' => 'preview-limit-report wikitable'
+               ] ) .
+                       Html::openElement( 'tbody' );
+
+               foreach ( $output->getLimitReportData()['limitreport'] as $key => $value ) {
+                       if ( Hooks::run( 'ParserLimitReportFormat',
+                               [ $key, &$value, &$limitReport, true, true ]
+                       ) ) {
+                               $keyMsg = wfMessage( "limitreport-$key" );
+                               $valueMsg = wfMessage(
+                                       [ "limitreport-$key-value-html", "limitreport-$key-value" ]
+                               );
+                               if ( !$valueMsg->exists() ) {
+                                       $valueMsg = new RawMessage( '$1' );
+                               }
+                               if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
+                                       // If it's a value/limit array, convert it for $1/$2
+                                       if ( is_array( $value ) && isset( $value['value'] ) ) {
+                                               $value = [ $value['value'], $value['limit'] ];
+                                       }
+                                       $limitReport .= Html::openElement( 'tr' ) .
+                                               Html::rawElement( 'th', null, $keyMsg->parse() ) .
+                                               Html::rawElement( 'td', null, $valueMsg->params( $value )->parse() ) .
+                                               Html::closeElement( 'tr' );
+                               }
+                       }
+               }
+
+               $limitReport .= Html::closeElement( 'tbody' ) .
+                       Html::closeElement( 'table' ) .
+                       Html::closeElement( 'div' );
+
+               return $limitReport;
        }
 
        protected function showStandardInputs( &$tabindex = 2 ) {
diff --git a/includes/MWGrants.php b/includes/MWGrants.php
new file mode 100644 (file)
index 0000000..58efdc7
--- /dev/null
@@ -0,0 +1,214 @@
+<?php
+/**
+ * Functions and constants to deal with grants
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/**
+ * A collection of public static functions to deal with grants.
+ */
+class MWGrants {
+
+       /**
+        * List all known grants.
+        * @return array
+        */
+       public static function getValidGrants() {
+               global $wgGrantPermissions;
+
+               return array_keys( $wgGrantPermissions );
+       }
+
+       /**
+        * Map all grants to corresponding user rights.
+        * @return array grant => array of rights
+        */
+       public static function getRightsByGrant() {
+               global $wgGrantPermissions;
+
+               $res = [];
+               foreach ( $wgGrantPermissions as $grant => $rights ) {
+                       $res[$grant] = array_keys( array_filter( $rights ) );
+               }
+               return $res;
+       }
+
+       /**
+        * Fetch the display name of the grant
+        * @param string $grant
+        * @param Language|string|null $lang
+        * @return string Grant description
+        */
+       public static function grantName( $grant, $lang = null ) {
+               // Give grep a chance to find the usages:
+               // grant-blockusers, grant-createeditmovepage, grant-delete,
+               // grant-editinterface, grant-editmycssjs, grant-editmywatchlist,
+               // grant-editpage, grant-editprotected, grant-highvolume,
+               // grant-oversight, grant-patrol, grant-protect, grant-rollback,
+               // grant-sendemail, grant-uploadeditmovefile, grant-uploadfile,
+               // grant-basic, grant-viewdeleted, grant-viewmywatchlist,
+               // grant-createaccount
+               $msg = wfMessage( "grant-$grant" );
+               if ( $lang !== null ) {
+                       if ( is_string( $lang ) ) {
+                               $lang = Language::factory( $lang );
+                       }
+                       $msg->inLanguage( $lang );
+               }
+               if ( !$msg->exists() ) {
+                       $msg = wfMessage( 'grant-generic', $grant );
+                       if ( $lang ) {
+                               $msg->inLanguage( $lang );
+                       }
+               }
+               return $msg->text();
+       }
+
+       /**
+        * Fetch the display names for the grants.
+        * @param string[] $grants
+        * @param Language|string|null $lang
+        * @return string[] Corresponding grant descriptions
+        */
+       public static function grantNames( array $grants, $lang = null ) {
+               if ( $lang !== null ) {
+                       if ( is_string( $lang ) ) {
+                               $lang = Language::factory( $lang );
+                       }
+               }
+
+               $ret = [];
+               foreach ( $grants as $grant ) {
+                       $ret[] = self::grantName( $grant, $lang );
+               }
+               return $ret;
+       }
+
+       /**
+        * Fetch the rights allowed by a set of grants.
+        * @param string[]|string $grants
+        * @return string[]
+        */
+       public static function getGrantRights( $grants ) {
+               global $wgGrantPermissions;
+
+               $rights = [];
+               foreach ( (array)$grants as $grant ) {
+                       if ( isset( $wgGrantPermissions[$grant] ) ) {
+                               $rights = array_merge( $rights, array_keys( array_filter( $wgGrantPermissions[$grant] ) ) );
+                       }
+               }
+               return array_unique( $rights );
+       }
+
+       /**
+        * Test that all grants in the list are known.
+        * @param string[] $grants
+        * @return bool
+        */
+       public static function grantsAreValid( array $grants ) {
+               return array_diff( $grants, self::getValidGrants() ) === [];
+       }
+
+       /**
+        * Divide the grants into groups.
+        * @param string[]|null $grantsFilter
+        * @return array Map of (group => (grant list))
+        */
+       public static function getGrantGroups( $grantsFilter = null ) {
+               global $wgGrantPermissions, $wgGrantPermissionGroups;
+
+               if ( is_array( $grantsFilter ) ) {
+                       $grantsFilter = array_flip( $grantsFilter );
+               }
+
+               $groups = [];
+               foreach ( $wgGrantPermissions as $grant => $rights ) {
+                       if ( $grantsFilter !== null && !isset( $grantsFilter[$grant] ) ) {
+                               continue;
+                       }
+                       if ( isset( $wgGrantPermissionGroups[$grant] ) ) {
+                               $groups[$wgGrantPermissionGroups[$grant]][] = $grant;
+                       } else {
+                               $groups['other'][] = $grant;
+                       }
+               }
+
+               return $groups;
+       }
+
+       /**
+        * Get the list of grants that are hidden and should always be granted
+        * @return string[]
+        */
+       public static function getHiddenGrants() {
+               global $wgGrantPermissionGroups;
+
+               $grants = [];
+               foreach ( $wgGrantPermissionGroups as $grant => $group ) {
+                       if ( $group === 'hidden' ) {
+                               $grants[] = $grant;
+                       }
+               }
+               return $grants;
+       }
+
+       /**
+        * Generate a link to Special:ListGrants for a particular grant name.
+        *
+        * This should be used to link end users to a full description of what
+        * rights they are giving when they authorize a grant.
+        *
+        * @param string $grant the grant name
+        * @param Language|string|null $lang
+        * @return string (proto-relative) HTML link
+        */
+       public static function getGrantsLink( $grant, $lang = null ) {
+               return \Linker::linkKnown(
+                       \SpecialPage::getTitleFor( 'Listgrants', false, $grant ),
+                       htmlspecialchars( self::grantName( $grant, $lang ) )
+               );
+       }
+
+       /**
+        * Generate wikitext to display a list of grants
+        * @param string[]|null $grantsFilter If non-null, only display these grants.
+        * @param Language|string|null $lang
+        * @return string Wikitext
+        */
+       public static function getGrantsWikiText( $grantsFilter, $lang = null ) {
+               global $wgContLang;
+
+               if ( is_string( $lang ) ) {
+                       $lang = Language::factory( $lang );
+               } elseif ( $lang === null ) {
+                       $lang = $wgContLang;
+               }
+
+               $s = '';
+               foreach ( self::getGrantGroups( $grantsFilter ) as $group => $grants ) {
+                       if ( $group === 'hidden' ) {
+                               continue; // implicitly granted
+                       }
+                       $s .= "*<span class=\"mw-grantgroup\">" .
+                               wfMessage( "grant-group-$group" )->inLanguage( $lang )->text() . "</span>\n";
+                       $s .= ":" . $lang->semicolonList( self::grantNames( $grants, $lang ) ) . "\n";
+               }
+               return "$s\n";
+       }
+
+}
index 218337a..f21128e 100644 (file)
@@ -678,7 +678,7 @@ class MediaWiki {
         * @param IContextSource $context
         * @return string|bool Either "local" or "remote" if in the farm, false otherwise
         */
-       private function getUrlDomainDistance( $url, IContextSource $context ) {
+       private static function getUrlDomainDistance( $url, IContextSource $context ) {
                static $relevantKeys = [ 'host' => true, 'port' => true ];
 
                $infoCandidate = wfParseUrl( $url );
index f91bbae..ba8b71b 100644 (file)
@@ -3,6 +3,7 @@ namespace MediaWiki;
 
 use Config;
 use ConfigFactory;
+use CryptHKDF;
 use CryptRand;
 use EventRelayerGroup;
 use GenderCache;
@@ -19,6 +20,7 @@ use MediaWiki\Services\SalvageableService;
 use MediaWiki\Services\ServiceContainer;
 use MediaWiki\Services\NoSuchServiceException;
 use MWException;
+use MimeAnalyzer;
 use ObjectCache;
 use ProxyLookup;
 use SearchEngine;
@@ -181,7 +183,7 @@ class MediaWikiServices extends ServiceContainer {
 
                $oldInstance = self::$instance;
 
-               self::$instance = self::newInstance( $bootstrapConfig );
+               self::$instance = self::newInstance( $bootstrapConfig, 'load' );
                self::$instance->importWiring( $oldInstance, [ 'BootstrapConfig' ] );
 
                if ( $quick === 'quick' ) {
@@ -531,6 +533,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'CryptRand' );
        }
 
+       /**
+        * @since 1.28
+        * @return CryptHKDF
+        */
+       public function getCryptHKDF() {
+               return $this->getService( 'CryptHKDF' );
+       }
+
        /**
         * @since 1.28
         * @return MediaHandlerFactory
@@ -539,6 +549,14 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'MediaHandlerFactory' );
        }
 
+       /**
+        * @since 1.28
+        * @return MimeAnalyzer
+        */
+       public function getMimeAnalyzer() {
+               return $this->getService( 'MimeAnalyzer' );
+       }
+
        /**
         * @since 1.28
         * @return ProxyLookup
index 54d58d2..c03bce7 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 /**
- * Module defining helper functions for detecting and dealing with MIME types.
- *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  *
  * @file
  */
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Logger\LoggerFactory;
 
-/**
- * Defines a set of well known MIME types
- * This is used as a fallback to mime.types files.
- * An extensive list of well known MIME types is provided by
- * the file mime.types in the includes directory.
- *
- * This list concatenated with mime.types is used to create a MIME <-> ext
- * map. Each line contains a MIME type followed by a space separated list of
- * extensions. If multiple extensions for a single MIME type exist or if
- * multiple MIME types exist for a single extension then in most cases
- * MediaWiki assumes that the first extension following the MIME type is the
- * canonical extension, and the first time a MIME type appears for a certain
- * extension is considered the canonical MIME type.
- *
- * (Note that appending $wgMimeTypeFile to the end of MM_WELL_KNOWN_MIME_TYPES
- * sucks because you can't redefine canonical types. This could be fixed by
- * appending MM_WELL_KNOWN_MIME_TYPES behind $wgMimeTypeFile, but who knows
- * what will break? In practice this probably isn't a problem anyway -- Bryan)
- */
-define( 'MM_WELL_KNOWN_MIME_TYPES', <<<END_STRING
-application/ogg ogx ogg ogm ogv oga spx
-application/pdf pdf
-application/vnd.oasis.opendocument.chart odc
-application/vnd.oasis.opendocument.chart-template otc
-application/vnd.oasis.opendocument.database odb
-application/vnd.oasis.opendocument.formula odf
-application/vnd.oasis.opendocument.formula-template otf
-application/vnd.oasis.opendocument.graphics odg
-application/vnd.oasis.opendocument.graphics-template otg
-application/vnd.oasis.opendocument.image odi
-application/vnd.oasis.opendocument.image-template oti
-application/vnd.oasis.opendocument.presentation odp
-application/vnd.oasis.opendocument.presentation-template otp
-application/vnd.oasis.opendocument.spreadsheet ods
-application/vnd.oasis.opendocument.spreadsheet-template ots
-application/vnd.oasis.opendocument.text odt
-application/vnd.oasis.opendocument.text-master otm
-application/vnd.oasis.opendocument.text-template ott
-application/vnd.oasis.opendocument.text-web oth
-application/javascript js
-application/x-shockwave-flash swf
-audio/midi mid midi kar
-audio/mpeg mpga mpa mp2 mp3
-audio/x-aiff aif aiff aifc
-audio/x-wav wav
-audio/ogg oga spx ogg
-image/x-bmp bmp
-image/gif gif
-image/jpeg jpeg jpg jpe
-image/png png
-image/svg+xml svg
-image/svg svg
-image/tiff tiff tif
-image/vnd.djvu djvu
-image/x.djvu djvu
-image/x-djvu djvu
-image/x-portable-pixmap ppm
-image/x-xcf xcf
-text/plain txt
-text/html html htm
-video/ogg ogv ogm ogg
-video/mpeg mpg mpeg
-END_STRING
-);
-
-/**
- * Defines a set of well known MIME info entries
- * This is used as a fallback to mime.info files.
- * An extensive list of well known MIME types is provided by
- * the file mime.info in the includes directory.
- */
-define( 'MM_WELL_KNOWN_MIME_INFO', <<<END_STRING
-application/pdf [OFFICE]
-application/vnd.oasis.opendocument.chart [OFFICE]
-application/vnd.oasis.opendocument.chart-template [OFFICE]
-application/vnd.oasis.opendocument.database [OFFICE]
-application/vnd.oasis.opendocument.formula [OFFICE]
-application/vnd.oasis.opendocument.formula-template [OFFICE]
-application/vnd.oasis.opendocument.graphics [OFFICE]
-application/vnd.oasis.opendocument.graphics-template [OFFICE]
-application/vnd.oasis.opendocument.image [OFFICE]
-application/vnd.oasis.opendocument.image-template [OFFICE]
-application/vnd.oasis.opendocument.presentation [OFFICE]
-application/vnd.oasis.opendocument.presentation-template [OFFICE]
-application/vnd.oasis.opendocument.spreadsheet [OFFICE]
-application/vnd.oasis.opendocument.spreadsheet-template [OFFICE]
-application/vnd.oasis.opendocument.text [OFFICE]
-application/vnd.oasis.opendocument.text-template [OFFICE]
-application/vnd.oasis.opendocument.text-master [OFFICE]
-application/vnd.oasis.opendocument.text-web [OFFICE]
-application/javascript text/javascript application/x-javascript [EXECUTABLE]
-application/x-shockwave-flash [MULTIMEDIA]
-audio/midi [AUDIO]
-audio/x-aiff [AUDIO]
-audio/x-wav [AUDIO]
-audio/mp3 audio/mpeg [AUDIO]
-application/ogg audio/ogg video/ogg [MULTIMEDIA]
-image/x-bmp image/x-ms-bmp image/bmp [BITMAP]
-image/gif [BITMAP]
-image/jpeg [BITMAP]
-image/png [BITMAP]
-image/svg+xml [DRAWING]
-image/tiff [BITMAP]
-image/vnd.djvu [BITMAP]
-image/x-xcf [BITMAP]
-image/x-portable-pixmap [BITMAP]
-text/plain [TEXT]
-text/html [TEXT]
-video/ogg [VIDEO]
-video/mpeg [VIDEO]
-unknown/unknown application/octet-stream application/x-empty [UNKNOWN]
-END_STRING
-);
-
-/**
- * Implements functions related to MIME types such as detection and mapping to
- * file extension.
- *
- * Instances of this class are stateless, there only needs to be one global instance
- * of MimeMagic. Please use MimeMagic::singleton() to get that instance.
- */
-class MimeMagic {
-       /**
-        * @var array Mapping of media types to arrays of MIME types.
-        * This is used by findMediaType and getMediaType, respectively
-        */
-       protected $mMediaTypes = null;
-
-       /** @var array Map of MIME type aliases
-        */
-       protected $mMimeTypeAliases = null;
-
-       /** @var array Map of MIME types to file extensions (as a space separated list)
-        */
-       protected $mMimeToExt = null;
-
-       /** @var array Map of file extensions types to MIME types (as a space separated list)
-        */
-       public $mExtToMime = null;
-
-       /** @var IEContentAnalyzer
-        */
-       protected $mIEAnalyzer;
-
-       /** @var string Extra MIME types, set for example by media handling extensions
-        */
-       private $mExtraTypes = '';
-
-       /** @var string Extra MIME info, set for example by media handling extensions
-        */
-       private $mExtraInfo = '';
-
-       /** @var Config */
-       private $mConfig;
-
-       /** @var MimeMagic The singleton instance
-        */
-       private static $instance = null;
-
-       /** Initializes the MimeMagic object. This is called by MimeMagic::singleton().
-        *
-        * This constructor parses the mime.types and mime.info files and build internal mappings.
-        *
-        * @todo Make this constructor private once everything uses the singleton instance
-        * @param Config $config
-        */
-       function __construct( Config $config = null ) {
-               if ( !$config ) {
-                       wfDebug( __METHOD__ . ' called with no Config instance passed to it' );
-                       $config = ConfigFactory::getDefaultInstance()->makeConfig( 'main' );
-               }
-               $this->mConfig = $config;
-
-               /**
-                *   --- load mime.types ---
-                */
-
-               global $IP;
-
-               # Allow media handling extensions adding MIME-types and MIME-info
-               Hooks::run( 'MimeMagicInit', [ $this ] );
-
-               $types = MM_WELL_KNOWN_MIME_TYPES;
-
-               $mimeTypeFile = $this->mConfig->get( 'MimeTypeFile' );
-               if ( $mimeTypeFile == 'includes/mime.types' ) {
-                       $mimeTypeFile = "$IP/$mimeTypeFile";
-               }
-
-               if ( $mimeTypeFile ) {
-                       if ( is_file( $mimeTypeFile ) && is_readable( $mimeTypeFile ) ) {
-                               wfDebug( __METHOD__ . ": loading mime types from $mimeTypeFile\n" );
-                               $types .= "\n";
-                               $types .= file_get_contents( $mimeTypeFile );
-                       } else {
-                               wfDebug( __METHOD__ . ": can't load mime types from $mimeTypeFile\n" );
-                       }
-               } else {
-                       wfDebug( __METHOD__ . ": no mime types file defined, using built-ins only.\n" );
-               }
-
-               $types .= "\n" . $this->mExtraTypes;
-
-               $types = str_replace( [ "\r\n", "\n\r", "\n\n", "\r\r", "\r" ], "\n", $types );
-               $types = str_replace( "\t", " ", $types );
-
-               $this->mMimeToExt = [];
-               $this->mExtToMime = [];
-
-               $lines = explode( "\n", $types );
-               foreach ( $lines as $s ) {
-                       $s = trim( $s );
-                       if ( empty( $s ) ) {
-                               continue;
-                       }
-                       if ( strpos( $s, '#' ) === 0 ) {
-                               continue;
-                       }
-
-                       $s = strtolower( $s );
-                       $i = strpos( $s, ' ' );
-
-                       if ( $i === false ) {
-                               continue;
-                       }
-
-                       $mime = substr( $s, 0, $i );
-                       $ext = trim( substr( $s, $i + 1 ) );
-
-                       if ( empty( $ext ) ) {
-                               continue;
-                       }
-
-                       if ( !empty( $this->mMimeToExt[$mime] ) ) {
-                               $this->mMimeToExt[$mime] .= ' ' . $ext;
-                       } else {
-                               $this->mMimeToExt[$mime] = $ext;
-                       }
-
-                       $extensions = explode( ' ', $ext );
-
-                       foreach ( $extensions as $e ) {
-                               $e = trim( $e );
-                               if ( empty( $e ) ) {
-                                       continue;
-                               }
-
-                               if ( !empty( $this->mExtToMime[$e] ) ) {
-                                       $this->mExtToMime[$e] .= ' ' . $mime;
-                               } else {
-                                       $this->mExtToMime[$e] = $mime;
-                               }
-                       }
-               }
-
-               /**
-                *   --- load mime.info ---
-                */
-
-               $mimeInfoFile = $this->mConfig->get( 'MimeInfoFile' );
-               if ( $mimeInfoFile == 'includes/mime.info' ) {
-                       $mimeInfoFile = "$IP/$mimeInfoFile";
-               }
-
-               $info = MM_WELL_KNOWN_MIME_INFO;
-
-               if ( $mimeInfoFile ) {
-                       if ( is_file( $mimeInfoFile ) && is_readable( $mimeInfoFile ) ) {
-                               wfDebug( __METHOD__ . ": loading mime info from $mimeInfoFile\n" );
-                               $info .= "\n";
-                               $info .= file_get_contents( $mimeInfoFile );
-                       } else {
-                               wfDebug( __METHOD__ . ": can't load mime info from $mimeInfoFile\n" );
-                       }
-               } else {
-                       wfDebug( __METHOD__ . ": no mime info file defined, using built-ins only.\n" );
-               }
-
-               $info .= "\n" . $this->mExtraInfo;
-
-               $info = str_replace( [ "\r\n", "\n\r", "\n\n", "\r\r", "\r" ], "\n", $info );
-               $info = str_replace( "\t", " ", $info );
-
-               $this->mMimeTypeAliases = [];
-               $this->mMediaTypes = [];
-
-               $lines = explode( "\n", $info );
-               foreach ( $lines as $s ) {
-                       $s = trim( $s );
-                       if ( empty( $s ) ) {
-                               continue;
-                       }
-                       if ( strpos( $s, '#' ) === 0 ) {
-                               continue;
-                       }
-
-                       $s = strtolower( $s );
-                       $i = strpos( $s, ' ' );
-
-                       if ( $i === false ) {
-                               continue;
-                       }
-
-                       # print "processing MIME INFO line $s<br>";
-
-                       $match = [];
-                       if ( preg_match( '!\[\s*(\w+)\s*\]!', $s, $match ) ) {
-                               $s = preg_replace( '!\[\s*(\w+)\s*\]!', '', $s );
-                               $mtype = trim( strtoupper( $match[1] ) );
-                       } else {
-                               $mtype = MEDIATYPE_UNKNOWN;
-                       }
-
-                       $m = explode( ' ', $s );
-
-                       if ( !isset( $this->mMediaTypes[$mtype] ) ) {
-                               $this->mMediaTypes[$mtype] = [];
-                       }
-
-                       foreach ( $m as $mime ) {
-                               $mime = trim( $mime );
-                               if ( empty( $mime ) ) {
-                                       continue;
-                               }
-
-                               $this->mMediaTypes[$mtype][] = $mime;
-                       }
-
-                       if ( count( $m ) > 1 ) {
-                               $main = $m[0];
-                               $mCount = count( $m );
-                               for ( $i = 1; $i < $mCount; $i += 1 ) {
-                                       $mime = $m[$i];
-                                       $this->mMimeTypeAliases[$mime] = $main;
-                               }
-                       }
-               }
-       }
-
+class MimeMagic extends MimeAnalyzer {
        /**
         * Get an instance of this class
         * @return MimeMagic
+        * @deprecated since 1.28
         */
        public static function singleton() {
-               if ( self::$instance === null ) {
-                       self::$instance = new MimeMagic(
-                               ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
-                       );
-               }
-               return self::$instance;
-       }
-
-       /**
-        * Adds to the list mapping MIME to file extensions.
-        * As an extension author, you are encouraged to submit patches to
-        * MediaWiki's core to add new MIME types to mime.types.
-        * @param string $types
-        */
-       public function addExtraTypes( $types ) {
-               $this->mExtraTypes .= "\n" . $types;
-       }
-
-       /**
-        * Adds to the list mapping MIME to media type.
-        * As an extension author, you are encouraged to submit patches to
-        * MediaWiki's core to add new MIME info to mime.info.
-        * @param string $info
-        */
-       public function addExtraInfo( $info ) {
-               $this->mExtraInfo .= "\n" . $info;
-       }
-
-       /**
-        * Returns a list of file extensions for a given MIME type as a space
-        * separated string or null if the MIME type was unrecognized. Resolves
-        * MIME type aliases.
-        *
-        * @param string $mime
-        * @return string|null
-        */
-       public function getExtensionsForType( $mime ) {
-               $mime = strtolower( $mime );
-
-               // Check the mime-to-ext map
-               if ( isset( $this->mMimeToExt[$mime] ) ) {
-                       return $this->mMimeToExt[$mime];
-               }
-
-               // Resolve the MIME type to the canonical type
-               if ( isset( $this->mMimeTypeAliases[$mime] ) ) {
-                       $mime = $this->mMimeTypeAliases[$mime];
-                       if ( isset( $this->mMimeToExt[$mime] ) ) {
-                               return $this->mMimeToExt[$mime];
-                       }
-               }
-
-               return null;
+               return MediaWikiServices::getInstance()->getMIMEAnalyzer();
        }
 
        /**
-        * Returns a list of MIME types for a given file extension as a space
-        * separated string or null if the extension was unrecognized.
-        *
-        * @param string $ext
-        * @return string|null
-        */
-       public function getTypesForExtension( $ext ) {
-               $ext = strtolower( $ext );
-
-               $r = isset( $this->mExtToMime[$ext] ) ? $this->mExtToMime[$ext] : null;
-               return $r;
-       }
-
-       /**
-        * Returns a single MIME type for a given file extension or null if unknown.
-        * This is always the first type from the list returned by getTypesForExtension($ext).
-        *
-        * @param string $ext
-        * @return string|null
-        */
-       public function guessTypesForExtension( $ext ) {
-               $m = $this->getTypesForExtension( $ext );
-               if ( is_null( $m ) ) {
-                       return null;
-               }
-
-               // TODO: Check if this is needed; strtok( $m, ' ' ) should be sufficient
-               $m = trim( $m );
-               $m = preg_replace( '/\s.*$/', '', $m );
-
-               return $m;
-       }
-
-       /**
-        * Tests if the extension matches the given MIME type. Returns true if a
-        * match was found, null if the MIME type is unknown, and false if the
-        * MIME type is known but no matches where found.
-        *
-        * @param string $extension
-        * @param string $mime
-        * @return bool|null
-        */
-       public function isMatchingExtension( $extension, $mime ) {
-               $ext = $this->getExtensionsForType( $mime );
-
-               if ( !$ext ) {
-                       return null; // Unknown MIME type
-               }
-
-               $ext = explode( ' ', $ext );
-
-               $extension = strtolower( $extension );
-               return in_array( $extension, $ext );
-       }
-
-       /**
-        * Returns true if the MIME type is known to represent an image format
-        * supported by the PHP GD library.
-        *
-        * @param string $mime
-        *
-        * @return bool
-        */
-       public function isPHPImageType( $mime ) {
-               // As defined by imagegetsize and image_type_to_mime
-               static $types = [
-                       'image/gif', 'image/jpeg', 'image/png',
-                       'image/x-bmp', 'image/xbm', 'image/tiff',
-                       'image/jp2', 'image/jpeg2000', 'image/iff',
-                       'image/xbm', 'image/x-xbitmap',
-                       'image/vnd.wap.wbmp', 'image/vnd.xiff',
-                       'image/x-photoshop',
-                       'application/x-shockwave-flash',
-               ];
-
-               return in_array( $mime, $types );
-       }
-
-       /**
-        * Returns true if the extension represents a type which can
-        * be reliably detected from its content. Use this to determine
-        * whether strict content checks should be applied to reject
-        * invalid uploads; if we can't identify the type we won't
-        * be able to say if it's invalid.
-        *
-        * @todo Be more accurate when using fancy MIME detector plugins;
-        *       right now this is the bare minimum getimagesize() list.
-        * @param string $extension
-        * @return bool
-        */
-       function isRecognizableExtension( $extension ) {
-               static $types = [
-                       // Types recognized by getimagesize()
-                       'gif', 'jpeg', 'jpg', 'png', 'swf', 'psd',
-                       'bmp', 'tiff', 'tif', 'jpc', 'jp2',
-                       'jpx', 'jb2', 'swc', 'iff', 'wbmp',
-                       'xbm',
-
-                       // Formats we recognize magic numbers for
-                       'djvu', 'ogx', 'ogg', 'ogv', 'oga', 'spx',
-                       'mid', 'pdf', 'wmf', 'xcf', 'webm', 'mkv', 'mka',
-                       'webp',
-
-                       // XML formats we sure hope we recognize reliably
-                       'svg',
-               ];
-               return in_array( strtolower( $extension ), $types );
-       }
-
-       /**
-        * Improves a MIME type using the file extension. Some file formats are very generic,
-        * so their MIME type is not very meaningful. A more useful MIME type can be derived
-        * by looking at the file extension. Typically, this method would be called on the
-        * result of guessMimeType().
-        *
-        * @param string $mime The MIME type, typically guessed from a file's content.
-        * @param string $ext The file extension, as taken from the file name
-        *
-        * @return string The MIME type
-        */
-       public function improveTypeFromExtension( $mime, $ext ) {
-               if ( $mime === 'unknown/unknown' ) {
-                       if ( $this->isRecognizableExtension( $ext ) ) {
-                               wfDebug( __METHOD__ . ': refusing to guess mime type for .' .
-                                       "$ext file, we should have recognized it\n" );
-                       } else {
-                               // Not something we can detect, so simply
-                               // trust the file extension
-                               $mime = $this->guessTypesForExtension( $ext );
-                       }
-               } elseif ( $mime === 'application/x-opc+zip' ) {
-                       if ( $this->isMatchingExtension( $ext, $mime ) ) {
-                               // A known file extension for an OPC file,
-                               // find the proper MIME type for that file extension
-                               $mime = $this->guessTypesForExtension( $ext );
-                       } else {
-                               wfDebug( __METHOD__ . ": refusing to guess better type for $mime file, " .
-                                       ".$ext is not a known OPC extension.\n" );
-                               $mime = 'application/zip';
-                       }
-               } elseif ( $mime === 'text/plain' && $this->findMediaType( ".$ext" ) === MEDIATYPE_TEXT ) {
-                       // Textual types are sometimes not recognized properly.
-                       // If detected as text/plain, and has an extension which is textual
-                       // improve to the extension's type. For example, csv and json are often
-                       // misdetected as text/plain.
-                       $mime = $this->guessTypesForExtension( $ext );
-               }
-
-               # Media handling extensions can improve the MIME detected
-               Hooks::run( 'MimeMagicImproveFromExtension', [ $this, $ext, &$mime ] );
-
-               if ( isset( $this->mMimeTypeAliases[$mime] ) ) {
-                       $mime = $this->mMimeTypeAliases[$mime];
-               }
-
-               wfDebug( __METHOD__ . ": improved mime type for .$ext: $mime\n" );
-               return $mime;
-       }
-
-       /**
-        * MIME type detection. This uses detectMimeType to detect the MIME type
-        * of the file, but applies additional checks to determine some well known
-        * file formats that may be missed or misinterpreted by the default MIME
-        * detection (namely XML based formats like XHTML or SVG, as well as ZIP
-        * based formats like OPC/ODF files).
-        *
-        * @param string $file The file to check
-        * @param string|bool $ext The file extension, or true (default) to extract it from the filename.
-        *   Set it to false to ignore the extension. DEPRECATED! Set to false, use
-        *   improveTypeFromExtension($mime, $ext) later to improve MIME type.
-        *
-        * @return string The MIME type of $file
-        */
-       public function guessMimeType( $file, $ext = true ) {
-               if ( $ext ) { // TODO: make $ext default to false. Or better, remove it.
-                       wfDebug( __METHOD__ . ": WARNING: use of the \$ext parameter is deprecated. " .
-                               "Use improveTypeFromExtension(\$mime, \$ext) instead.\n" );
-               }
-
-               $mime = $this->doGuessMimeType( $file, $ext );
-
-               if ( !$mime ) {
-                       wfDebug( __METHOD__ . ": internal type detection failed for $file (.$ext)...\n" );
-                       $mime = $this->detectMimeType( $file, $ext );
-               }
-
-               if ( isset( $this->mMimeTypeAliases[$mime] ) ) {
-                       $mime = $this->mMimeTypeAliases[$mime];
-               }
-
-               wfDebug( __METHOD__ . ": guessed mime type of $file: $mime\n" );
-               return $mime;
-       }
-
-       /**
-        * Guess the MIME type from the file contents.
-        *
-        * @todo Remove $ext param
-        *
-        * @param string $file
-        * @param mixed $ext
-        * @return bool|string
-        * @throws MWException
+        * @param array $params
+        * @param Config $mainConfig
+        * @return array
         */
-       private function doGuessMimeType( $file, $ext ) {
-               // Read a chunk of the file
-               MediaWiki\suppressWarnings();
-               $f = fopen( $file, 'rb' );
-               MediaWiki\restoreWarnings();
-
-               if ( !$f ) {
-                       return 'unknown/unknown';
-               }
-
-               $fsize = filesize( $file );
-               if ( $fsize === false ) {
-                       return 'unknown/unknown';
-               }
-
-               $head = fread( $f, 1024 );
-               $tailLength = min( 65558, $fsize ); // 65558 = maximum size of a zip EOCDR
-               if ( fseek( $f, -1 * $tailLength, SEEK_END ) === -1 ) {
-                       throw new MWException(
-                               "Seeking $tailLength bytes from EOF failed in " . __METHOD__ );
-               }
-               $tail = $tailLength ? fread( $f, $tailLength ) : '';
-               fclose( $f );
-
-               wfDebug( __METHOD__ . ": analyzing head and tail of $file for magic numbers.\n" );
-
-               // Hardcode a few magic number checks...
-               $headers = [
-                       // Multimedia...
-                       'MThd'             => 'audio/midi',
-                       'OggS'             => 'application/ogg',
-
-                       // Image formats...
-                       // Note that WMF may have a bare header, no magic number.
-                       "\x01\x00\x09\x00" => 'application/x-msmetafile', // Possibly prone to false positives?
-                       "\xd7\xcd\xc6\x9a" => 'application/x-msmetafile',
-                       '%PDF'             => 'application/pdf',
-                       'gimp xcf'         => 'image/x-xcf',
-
-                       // Some forbidden fruit...
-                       'MZ'               => 'application/octet-stream', // DOS/Windows executable
-                       "\xca\xfe\xba\xbe" => 'application/octet-stream', // Mach-O binary
-                       "\x7fELF"          => 'application/octet-stream', // ELF binary
-               ];
-
-               foreach ( $headers as $magic => $candidate ) {
-                       if ( strncmp( $head, $magic, strlen( $magic ) ) == 0 ) {
-                               wfDebug( __METHOD__ . ": magic header in $file recognized as $candidate\n" );
-                               return $candidate;
-                       }
-               }
-
-               /* Look for WebM and Matroska files */
-               if ( strncmp( $head, pack( "C4", 0x1a, 0x45, 0xdf, 0xa3 ), 4 ) == 0 ) {
-                       $doctype = strpos( $head, "\x42\x82" );
-                       if ( $doctype ) {
-                               // Next byte is datasize, then data (sizes larger than 1 byte are very stupid muxers)
-                               $data = substr( $head, $doctype + 3, 8 );
-                               if ( strncmp( $data, "matroska", 8 ) == 0 ) {
-                                       wfDebug( __METHOD__ . ": recognized file as video/x-matroska\n" );
-                                       return "video/x-matroska";
-                               } elseif ( strncmp( $data, "webm", 4 ) == 0 ) {
-                                       wfDebug( __METHOD__ . ": recognized file as video/webm\n" );
-                                       return "video/webm";
-                               }
-                       }
-                       wfDebug( __METHOD__ . ": unknown EBML file\n" );
-                       return "unknown/unknown";
-               }
-
-               /* Look for WebP */
-               if ( strncmp( $head, "RIFF", 4 ) == 0 && strncmp( substr( $head, 8, 7 ), "WEBPVP8", 7 ) == 0 ) {
-                       wfDebug( __METHOD__ . ": recognized file as image/webp\n" );
-                       return "image/webp";
-               }
-
-               /**
-                * Look for PHP.  Check for this before HTML/XML...  Warning: this is a
-                * heuristic, and won't match a file with a lot of non-PHP before.  It
-                * will also match text files which could be PHP. :)
-                *
-                * @todo FIXME: For this reason, the check is probably useless -- an attacker
-                * could almost certainly just pad the file with a lot of nonsense to
-                * circumvent the check in any case where it would be a security
-                * problem.  On the other hand, it causes harmful false positives (bug
-                * 16583).  The heuristic has been cut down to exclude three-character
-                * strings like "<? ", but should it be axed completely?
-                */
-               if ( ( strpos( $head, '<?php' ) !== false ) ||
-                       ( strpos( $head, "<\x00?\x00p\x00h\x00p" ) !== false ) ||
-                       ( strpos( $head, "<\x00?\x00 " ) !== false ) ||
-                       ( strpos( $head, "<\x00?\x00\n" ) !== false ) ||
-                       ( strpos( $head, "<\x00?\x00\t" ) !== false ) ||
-                       ( strpos( $head, "<\x00?\x00=" ) !== false ) ) {
-
-                       wfDebug( __METHOD__ . ": recognized $file as application/x-php\n" );
-                       return 'application/x-php';
-               }
-
-               /**
-                * look for XML formats (XHTML and SVG)
-                */
-               $xml = new XmlTypeCheck( $file );
-               if ( $xml->wellFormed ) {
-                       $xmlMimeTypes = $this->mConfig->get( 'XMLMimeTypes' );
-                       if ( isset( $xmlMimeTypes[$xml->getRootElement()] ) ) {
-                               return $xmlMimeTypes[$xml->getRootElement()];
-                       } else {
-                               return 'application/xml';
-                       }
-               }
-
-               /**
-                * look for shell scripts
-                */
-               $script_type = null;
-
-               # detect by shebang
-               if ( substr( $head, 0, 2 ) == "#!" ) {
-                       $script_type = "ASCII";
-               } elseif ( substr( $head, 0, 5 ) == "\xef\xbb\xbf#!" ) {
-                       $script_type = "UTF-8";
-               } elseif ( substr( $head, 0, 7 ) == "\xfe\xff\x00#\x00!" ) {
-                       $script_type = "UTF-16BE";
-               } elseif ( substr( $head, 0, 7 ) == "\xff\xfe#\x00!" ) {
-                       $script_type = "UTF-16LE";
-               }
-
-               if ( $script_type ) {
-                       if ( $script_type !== "UTF-8" && $script_type !== "ASCII" ) {
-                               // Quick and dirty fold down to ASCII!
-                               $pack = [ 'UTF-16BE' => 'n*', 'UTF-16LE' => 'v*' ];
-                               $chars = unpack( $pack[$script_type], substr( $head, 2 ) );
-                               $head = '';
-                               foreach ( $chars as $codepoint ) {
-                                       if ( $codepoint < 128 ) {
-                                               $head .= chr( $codepoint );
-                                       } else {
-                                               $head .= '?';
+       public static function applyDefaultParameters( array $params, Config $mainConfig ) {
+               $logger = LoggerFactory::getInstance( 'Mime' );
+               $params += [
+                       'typeFile' => $mainConfig->get( 'MimeTypeFile' ),
+                       'infoFile' => $mainConfig->get( 'MimeInfoFile' ),
+                       'xmlTypes' => $mainConfig->get( 'XMLMimeTypes' ),
+                       'guessCallback' =>
+                               function ( $mimeAnalyzer, &$head, &$tail, $file, &$mime ) use ( $logger ) {
+                                       // Also test DjVu
+                                       $deja = new DjVuImage( $file );
+                                       if ( $deja->isValid() ) {
+                                               $logger->info( __METHOD__ . ": detected $file as image/vnd.djvu\n" );
+                                               $mime = 'image/vnd.djvu';
+
+                                               return;
                                        }
-                               }
-                       }
-
-                       $match = [];
-
-                       if ( preg_match( '%/?([^\s]+/)(\w+)%', $head, $match ) ) {
-                               $mime = "application/x-{$match[2]}";
-                               wfDebug( __METHOD__ . ": shell script recognized as $mime\n" );
-                               return $mime;
-                       }
-               }
-
-               // Check for ZIP variants (before getimagesize)
-               if ( strpos( $tail, "PK\x05\x06" ) !== false ) {
-                       wfDebug( __METHOD__ . ": ZIP header present in $file\n" );
-                       return $this->detectZipType( $head, $tail, $ext );
-               }
-
-               MediaWiki\suppressWarnings();
-               $gis = getimagesize( $file );
-               MediaWiki\restoreWarnings();
-
-               if ( $gis && isset( $gis['mime'] ) ) {
-                       $mime = $gis['mime'];
-                       wfDebug( __METHOD__ . ": getimagesize detected $file as $mime\n" );
-                       return $mime;
-               }
-
-               // Also test DjVu
-               $deja = new DjVuImage( $file );
-               if ( $deja->isValid() ) {
-                       wfDebug( __METHOD__ . ": detected $file as image/vnd.djvu\n" );
-                       return 'image/vnd.djvu';
-               }
-
-               # Media handling extensions can guess the MIME by content
-               # It's intentionally here so that if core is wrong about a type (false positive),
-               # people will hopefully nag and submit patches :)
-               $mime = false;
-               # Some strings by reference for performance - assuming well-behaved hooks
-               Hooks::run(
-                       'MimeMagicGuessFromContent',
-                       [ $this, &$head, &$tail, $file, &$mime ]
-               );
-
-               return $mime;
-       }
-
-       /**
-        * Detect application-specific file type of a given ZIP file from its
-        * header data.  Currently works for OpenDocument and OpenXML types...
-        * If can't tell, returns 'application/zip'.
-        *
-        * @param string $header Some reasonably-sized chunk of file header
-        * @param string|null $tail The tail of the file
-        * @param string|bool $ext The file extension, or true to extract it from the filename.
-        *   Set it to false (default) to ignore the extension. DEPRECATED! Set to false,
-        *   use improveTypeFromExtension($mime, $ext) later to improve MIME type.
-        *
-        * @return string
-        */
-       function detectZipType( $header, $tail = null, $ext = false ) {
-               if ( $ext ) { # TODO: remove $ext param
-                       wfDebug( __METHOD__ . ": WARNING: use of the \$ext parameter is deprecated. " .
-                               "Use improveTypeFromExtension(\$mime, \$ext) instead.\n" );
-               }
-
-               $mime = 'application/zip';
-               $opendocTypes = [
-                       'chart-template',
-                       'chart',
-                       'formula-template',
-                       'formula',
-                       'graphics-template',
-                       'graphics',
-                       'image-template',
-                       'image',
-                       'presentation-template',
-                       'presentation',
-                       'spreadsheet-template',
-                       'spreadsheet',
-                       'text-template',
-                       'text-master',
-                       'text-web',
-                       'text' ];
-
-               // http://lists.oasis-open.org/archives/office/200505/msg00006.html
-               $types = '(?:' . implode( '|', $opendocTypes ) . ')';
-               $opendocRegex = "/^mimetype(application\/vnd\.oasis\.opendocument\.$types)/";
-
-               $openxmlRegex = "/^\[Content_Types\].xml/";
-
-               if ( preg_match( $opendocRegex, substr( $header, 30 ), $matches ) ) {
-                       $mime = $matches[1];
-                       wfDebug( __METHOD__ . ": detected $mime from ZIP archive\n" );
-               } elseif ( preg_match( $openxmlRegex, substr( $header, 30 ) ) ) {
-                       $mime = "application/x-opc+zip";
-                       # TODO: remove the block below, as soon as improveTypeFromExtension is used everywhere
-                       if ( $ext !== true && $ext !== false ) {
-                               // These MIME's are stored in the database, where we don't really want
-                               // x-opc+zip, because we use it only for internal purposes
-                               if ( $this->isMatchingExtension( $ext, $mime ) ) {
-                                       /* A known file extension for an OPC file,
-                                        * find the proper mime type for that file extension
-                                        */
-                                       $mime = $this->guessTypesForExtension( $ext );
-                               } else {
-                                       $mime = "application/zip";
-                               }
-                       }
-                       wfDebug( __METHOD__ . ": detected an Open Packaging Conventions archive: $mime\n" );
-               } elseif ( substr( $header, 0, 8 ) == "\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1" &&
-                               ( $headerpos = strpos( $tail, "PK\x03\x04" ) ) !== false &&
-                               preg_match( $openxmlRegex, substr( $tail, $headerpos + 30 ) ) ) {
-                       if ( substr( $header, 512, 4 ) == "\xEC\xA5\xC1\x00" ) {
-                               $mime = "application/msword";
-                       }
-                       switch ( substr( $header, 512, 6 ) ) {
-                               case "\xEC\xA5\xC1\x00\x0E\x00":
-                               case "\xEC\xA5\xC1\x00\x1C\x00":
-                               case "\xEC\xA5\xC1\x00\x43\x00":
-                                       $mime = "application/vnd.ms-powerpoint";
-                                       break;
-                               case "\xFD\xFF\xFF\xFF\x10\x00":
-                               case "\xFD\xFF\xFF\xFF\x1F\x00":
-                               case "\xFD\xFF\xFF\xFF\x22\x00":
-                               case "\xFD\xFF\xFF\xFF\x23\x00":
-                               case "\xFD\xFF\xFF\xFF\x28\x00":
-                               case "\xFD\xFF\xFF\xFF\x29\x00":
-                               case "\xFD\xFF\xFF\xFF\x10\x02":
-                               case "\xFD\xFF\xFF\xFF\x1F\x02":
-                               case "\xFD\xFF\xFF\xFF\x22\x02":
-                               case "\xFD\xFF\xFF\xFF\x23\x02":
-                               case "\xFD\xFF\xFF\xFF\x28\x02":
-                               case "\xFD\xFF\xFF\xFF\x29\x02":
-                                       $mime = "application/vnd.msexcel";
-                                       break;
-                       }
-
-                       wfDebug( __METHOD__ . ": detected a MS Office document with OPC trailer\n" );
-               } else {
-                       wfDebug( __METHOD__ . ": unable to identify type of ZIP archive\n" );
-               }
-               return $mime;
-       }
-
-       /**
-        * Internal MIME type detection. Detection is done using an external
-        * program, if $wgMimeDetectorCommand is set. Otherwise, the fileinfo
-        * extension is tried if it is available. If detection fails and $ext
-        * is not false, the MIME type is guessed from the file extension,
-        * using guessTypesForExtension.
-        *
-        * If the MIME type is still unknown, getimagesize is used to detect the
-        * MIME type if the file is an image. If no MIME type can be determined,
-        * this function returns 'unknown/unknown'.
-        *
-        * @param string $file The file to check
-        * @param string|bool $ext The file extension, or true (default) to extract it from the filename.
-        *   Set it to false to ignore the extension. DEPRECATED! Set to false, use
-        *   improveTypeFromExtension($mime, $ext) later to improve MIME type.
-        *
-        * @return string The MIME type of $file
-        */
-       private function detectMimeType( $file, $ext = true ) {
-               /** @todo Make $ext default to false. Or better, remove it. */
-               if ( $ext ) {
-                       wfDebug( __METHOD__ . ": WARNING: use of the \$ext parameter is deprecated. "
-                               . "Use improveTypeFromExtension(\$mime, \$ext) instead.\n" );
-               }
-
-               $mimeDetectorCommand = $this->mConfig->get( 'MimeDetectorCommand' );
-               $m = null;
-               if ( $mimeDetectorCommand ) {
-                       $args = wfEscapeShellArg( $file );
-                       $m = wfShellExec( "$mimeDetectorCommand $args" );
-               } elseif ( function_exists( "finfo_open" ) && function_exists( "finfo_file" ) ) {
-                       $mime_magic_resource = finfo_open( FILEINFO_MIME );
-
-                       if ( $mime_magic_resource ) {
-                               $m = finfo_file( $mime_magic_resource, $file );
-                               finfo_close( $mime_magic_resource );
-                       } else {
-                               wfDebug( __METHOD__ . ": finfo_open failed on " . FILEINFO_MIME . "!\n" );
-                       }
-               } else {
-                       wfDebug( __METHOD__ . ": no magic mime detector found!\n" );
-               }
-
-               if ( $m ) {
-                       # normalize
-                       $m = preg_replace( '![;, ].*$!', '', $m ); # strip charset, etc
-                       $m = trim( $m );
-                       $m = strtolower( $m );
-
-                       if ( strpos( $m, 'unknown' ) !== false ) {
-                               $m = null;
-                       } else {
-                               wfDebug( __METHOD__ . ": magic mime type of $file: $m\n" );
-                               return $m;
-                       }
-               }
-
-               // If desired, look at extension as a fallback.
-               if ( $ext === true ) {
-                       $i = strrpos( $file, '.' );
-                       $ext = strtolower( $i ? substr( $file, $i + 1 ) : '' );
-               }
-               if ( $ext ) {
-                       if ( $this->isRecognizableExtension( $ext ) ) {
-                               wfDebug( __METHOD__ . ": refusing to guess mime type for .$ext file, "
-                                       . "we should have recognized it\n" );
-                       } else {
-                               $m = $this->guessTypesForExtension( $ext );
-                               if ( $m ) {
-                                       wfDebug( __METHOD__ . ": extension mime type of $file: $m\n" );
-                                       return $m;
-                               }
-                       }
-               }
-
-               // Unknown type
-               wfDebug( __METHOD__ . ": failed to guess mime type for $file!\n" );
-               return 'unknown/unknown';
-       }
-
-       /**
-        * Determine the media type code for a file, using its MIME type, name and
-        * possibly its contents.
-        *
-        * This function relies on the findMediaType(), mapping extensions and MIME
-        * types to media types.
-        *
-        * @todo analyse file if need be
-        * @todo look at multiple extension, separately and together.
-        *
-        * @param string $path Full path to the image file, in case we have to look at the contents
-        *        (if null, only the MIME type is used to determine the media type code).
-        * @param string $mime MIME type. If null it will be guessed using guessMimeType.
-        *
-        * @return string A value to be used with the MEDIATYPE_xxx constants.
-        */
-       function getMediaType( $path = null, $mime = null ) {
-               if ( !$mime && !$path ) {
-                       return MEDIATYPE_UNKNOWN;
-               }
-
-               // If MIME type is unknown, guess it
-               if ( !$mime ) {
-                       $mime = $this->guessMimeType( $path, false );
-               }
-
-               // Special code for ogg - detect if it's video (theora),
-               // else label it as sound.
-               if ( $mime == 'application/ogg' && file_exists( $path ) ) {
-
-                       // Read a chunk of the file
-                       $f = fopen( $path, "rt" );
-                       if ( !$f ) {
-                               return MEDIATYPE_UNKNOWN;
-                       }
-                       $head = fread( $f, 256 );
-                       fclose( $f );
-
-                       $head = str_replace( 'ffmpeg2theora', '', strtolower( $head ) );
-
-                       // This is an UGLY HACK, file should be parsed correctly
-                       if ( strpos( $head, 'theora' ) !== false ) {
-                               return MEDIATYPE_VIDEO;
-                       } elseif ( strpos( $head, 'vorbis' ) !== false ) {
-                               return MEDIATYPE_AUDIO;
-                       } elseif ( strpos( $head, 'flac' ) !== false ) {
-                               return MEDIATYPE_AUDIO;
-                       } elseif ( strpos( $head, 'speex' ) !== false ) {
-                               return MEDIATYPE_AUDIO;
-                       } else {
-                               return MEDIATYPE_MULTIMEDIA;
-                       }
-               }
-
-               $type = null;
-               // Check for entry for full MIME type
-               if ( $mime ) {
-                       $type = $this->findMediaType( $mime );
-                       if ( $type !== MEDIATYPE_UNKNOWN ) {
-                               return $type;
-                       }
-               }
-
-               // Check for entry for file extension
-               if ( $path ) {
-                       $i = strrpos( $path, '.' );
-                       $e = strtolower( $i ? substr( $path, $i + 1 ) : '' );
-
-                       // TODO: look at multi-extension if this fails, parse from full path
-                       $type = $this->findMediaType( '.' . $e );
-                       if ( $type !== MEDIATYPE_UNKNOWN ) {
-                               return $type;
-                       }
-               }
-
-               // Check major MIME type
-               if ( $mime ) {
-                       $i = strpos( $mime, '/' );
-                       if ( $i !== false ) {
-                               $major = substr( $mime, 0, $i );
-                               $type = $this->findMediaType( $major );
-                               if ( $type !== MEDIATYPE_UNKNOWN ) {
-                                       return $type;
-                               }
-                       }
-               }
+                                       // Some strings by reference for performance - assuming well-behaved hooks
+                                       Hooks::run(
+                                               'MimeMagicGuessFromContent',
+                                               [ $mimeAnalyzer, &$head, &$tail, $file, &$mime ]
+                                       );
+                               },
+                       'extCallback' => function ( $mimeAnalyzer, $ext, &$mime ) {
+                               // Media handling extensions can improve the MIME detected
+                               Hooks::run( 'MimeMagicImproveFromExtension', [ $mimeAnalyzer, $ext, &$mime ] );
+                       },
+                       'initCallback' => function ( $mimeAnalyzer ) {
+                               // Allow media handling extensions adding MIME-types and MIME-info
+                               Hooks::run( 'MimeMagicInit', [ $mimeAnalyzer ] );
+                       },
+                       'logger' => $logger
+               ];
 
-               if ( !$type ) {
-                       $type = MEDIATYPE_UNKNOWN;
+               if ( $params['infoFile'] === 'includes/mime.info' ) {
+                       $params['infoFile'] = __DIR__ . "/libs/mime/mime.info";
                }
 
-               return $type;
-       }
-
-       /**
-        * Returns a media code matching the given MIME type or file extension.
-        * File extensions are represented by a string starting with a dot (.) to
-        * distinguish them from MIME types.
-        *
-        * This function relies on the mapping defined by $this->mMediaTypes
-        * @access private
-        * @param string $extMime
-        * @return int|string
-        */
-       function findMediaType( $extMime ) {
-               if ( strpos( $extMime, '.' ) === 0 ) {
-                       // If it's an extension, look up the MIME types
-                       $m = $this->getTypesForExtension( substr( $extMime, 1 ) );
-                       if ( !$m ) {
-                               return MEDIATYPE_UNKNOWN;
-                       }
-
-                       $m = explode( ' ', $m );
-               } else {
-                       // Normalize MIME type
-                       if ( isset( $this->mMimeTypeAliases[$extMime] ) ) {
-                               $extMime = $this->mMimeTypeAliases[$extMime];
-                       }
-
-                       $m = [ $extMime ];
+               if ( $params['typeFile'] === 'includes/mime.types' ) {
+                       $params['typeFile'] = __DIR__ . "/libs/mime/mime.types";
                }
 
-               foreach ( $m as $mime ) {
-                       foreach ( $this->mMediaTypes as $type => $codes ) {
-                               if ( in_array( $mime, $codes, true ) ) {
-                                       return $type;
-                               }
-                       }
+               $detectorCmd = $mainConfig->get( 'MimeDetectorCommand' );
+               if ( $detectorCmd ) {
+                       $params['detectCallback'] = function ( $file ) use ( $detectorCmd ) {
+                               return wfShellExec( "$detectorCmd " . wfEscapeShellArg( $file ) );
+                       };
                }
 
-               return MEDIATYPE_UNKNOWN;
-       }
-
-       /**
-        * Get the MIME types that various versions of Internet Explorer would
-        * detect from a chunk of the content.
-        *
-        * @param string $fileName The file name (unused at present)
-        * @param string $chunk The first 256 bytes of the file
-        * @param string $proposed The MIME type proposed by the server
-        * @return array
-        */
-       public function getIEMimeTypes( $fileName, $chunk, $proposed ) {
-               $ca = $this->getIEContentAnalyzer();
-               return $ca->getRealMimesFromData( $fileName, $chunk, $proposed );
-       }
-
-       /**
-        * Get a cached instance of IEContentAnalyzer
-        *
-        * @return IEContentAnalyzer
-        */
-       protected function getIEContentAnalyzer() {
-               if ( is_null( $this->mIEAnalyzer ) ) {
-                       $this->mIEAnalyzer = new IEContentAnalyzer;
-               }
-               return $this->mIEAnalyzer;
+               return $params;
        }
 }
index a69c0e6..50f9eb9 100644 (file)
@@ -1782,7 +1782,9 @@ class OutputPage extends ContextSource {
                }
 
                // Include profiling data
-               $this->setLimitReportData( $parserOutput->getLimitReportData() );
+               if ( !$this->limitReportData ) {
+                       $this->setLimitReportData( $parserOutput->getLimitReportData() );
+               }
 
                // Link flags are ignored for now, but may in the future be
                // used to mark individual language links.
@@ -2929,12 +2931,14 @@ class OutputPage extends ContextSource {
                        }
                }
 
-               $chunks[] = ResourceLoader::makeInlineScript(
-                       ResourceLoader::makeConfigSetScript(
-                               [ 'wgPageParseReport' => $this->limitReportData ],
-                               true
-                       )
-               );
+               if ( $this->limitReportData ) {
+                       $chunks[] = ResourceLoader::makeInlineScript(
+                               ResourceLoader::makeConfigSetScript(
+                                       [ 'wgPageParseReport' => $this->limitReportData ],
+                                       true
+                               )
+                       );
+               }
 
                return self::combineWrappedStrings( $chunks );
        }
index 42b75f0..a071ff7 100644 (file)
@@ -184,12 +184,44 @@ return [
                );
        },
 
+       'CryptHKDF' => function( MediaWikiServices $services ) {
+               $config = $services->getMainConfig();
+
+               $secret = $config->get( 'HKDFSecret' ) ?: $config->get( 'SecretKey' );
+               if ( !$secret ) {
+                       throw new RuntimeException( "Cannot use MWCryptHKDF without a secret." );
+               }
+
+               // In HKDF, the context can be known to the attacker, but this will
+               // keep simultaneous runs from producing the same output.
+               $context = [ microtime(), getmypid(), gethostname() ];
+
+               // Setup salt cache. Use APC, or fallback to the main cache if it isn't setup
+               $cache = $services->getLocalServerObjectCache();
+               if ( $cache instanceof EmptyBagOStuff ) {
+                       $cache = ObjectCache::getLocalClusterInstance();
+               }
+
+               return new CryptHKDF( $secret, $config->get( 'HKDFAlgorithm' ),
+                       $cache, $context, $services->getCryptRand()
+               );
+       },
+
        'MediaHandlerFactory' => function( MediaWikiServices $services ) {
                return new MediaHandlerFactory(
                        $services->getMainConfig()->get( 'MediaHandlers' )
                );
        },
 
+       'MimeAnalyzer' => function( MediaWikiServices $services ) {
+               return new MimeMagic(
+                       MimeMagic::applyDefaultParameters(
+                               [],
+                               $services->getMainConfig()
+                       )
+               );
+       },
+
        'ProxyLookup' => function( MediaWikiServices $services ) {
                $mainConfig = $services->getMainConfig();
                return new ProxyLookup(
index 5a2492d..92cbe90 100644 (file)
@@ -21,6 +21,7 @@
 
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
 
 /**
  * Prepare an edit in shared cache so that it can be reused on edit
index 41f1ff9..40243c1 100644 (file)
        "apihelp-emailuser-param-text": "E-Mail-Inhalt.",
        "apihelp-emailuser-param-ccme": "Eine Kopie dieser E-Mail an mich senden.",
        "apihelp-emailuser-example-email": "Eine E-Mail an den Benutzer <kbd>WikiSysop</kbd> mit dem Text <kbd>Content</kbd> senden.",
-       "apihelp-expandtemplates-description": "Alle Vorlagen im Wikitext expandieren.",
+       "apihelp-expandtemplates-description": "Alle Vorlagen innerhalb des Wikitextes expandieren.",
        "apihelp-expandtemplates-param-title": "Titel der Seite.",
        "apihelp-expandtemplates-param-text": "Zu konvertierender Wikitext.",
        "apihelp-expandtemplates-param-revid": "Versionsnummer, die für die Anzeige von <nowiki>{{REVISIONID}}</nowiki> und ähnlichen Variablen verwendet wird.",
index 8ed1cf5..3ac5c4a 100644 (file)
        "apihelp-query+exturlusage-param-prop": "Qué piezas de información incluir:",
        "apihelp-query+exturlusage-paramvalue-prop-ids": "Añade el identificado de la página.",
        "apihelp-query+exturlusage-paramvalue-prop-title": "Agrega el título y el identificador del espacio de nombres de la página.",
+       "apihelp-query+exturlusage-paramvalue-prop-url": "Añade el URL utilizado en la página.",
        "apihelp-query+exturlusage-param-protocol": "Protocolo del URL. Si está vacío y se establece <var>$1query</var>, el protocolo es <kbd>http</kbd>. Deja vacío esto y <var>$1query</var> para listar todos los enlaces externos.",
        "apihelp-query+exturlusage-param-limit": "Cuántas páginas se devolverán.",
        "apihelp-query+exturlusage-example-simple": "Mostrar páginas que enlacen con <kbd>http://www.mediawiki.org</kbd>.",
index 435c6b4..321fb75 100644 (file)
        "apihelp-edit-param-tags": "Modifier les balises à appliquer à la version.",
        "apihelp-edit-param-minor": "Modification mineure.",
        "apihelp-edit-param-notminor": "Modification non mineure.",
-       "apihelp-edit-param-bot": "Marquer cette modification comme robot.",
+       "apihelp-edit-param-bot": "Marquer cette modification comme effectuée par un robot.",
        "apihelp-edit-param-basetimestamp": "Horodatage de la révision de base, utilisé pour détecter les conflits de modification. Peut être obtenu via [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "L'horodatage, lorsque le processus d'édition est démarré, est utilisé pour détecter les conflits de modification. Une valeur appropriée peut être obtenue en utilisant <var>[[Special:ApiHelp/main|curtimestamp]]</var> lors du démarrage du processus d'édition (par ex. en chargeant le contenu de la page à modifier).",
        "apihelp-edit-param-recreate": "Ignorer toutes les erreurs concernant la page \nqui a été supprimée entre-temps.",
        "apihelp-emailuser-param-text": "Corps du courriel.",
        "apihelp-emailuser-param-ccme": "M’envoyer une copie de ce courriel.",
        "apihelp-emailuser-example-email": "Envoyer un courriel à l’utilisateur <kbd>WikiSysop</kbd> avec le texte <kbd>Content</kbd>.",
-       "apihelp-expandtemplates-description": "Développe tous les modèles en wikitexte.",
+       "apihelp-expandtemplates-description": "Développe tous les modèles avec du wikitexte.",
        "apihelp-expandtemplates-param-title": "Titre de la page.",
        "apihelp-expandtemplates-param-text": "Wikitexte à convertir.",
        "apihelp-expandtemplates-param-revid": "ID de révision, pour <nowiki>{{REVISIONID}}</nowiki> et les variables semblables.",
index 9c8e67c..4c74147 100644 (file)
        "apihelp-emailuser-param-text": "Corpo do correo.",
        "apihelp-emailuser-param-ccme": "Enviarme unha copia deste correo.",
        "apihelp-emailuser-example-email": "Enviar un correo electrónico ó usuario <kbd>WikiSysop</kbd> co texto <kbd>Content</kbd>.",
-       "apihelp-expandtemplates-description": "Expandir tódolos modelos en wikitexto.",
+       "apihelp-expandtemplates-description": "Expandir tódolos modelos dentro do wikitexto.",
        "apihelp-expandtemplates-param-title": "Título da páxina.",
        "apihelp-expandtemplates-param-text": "Sintaxis wiki a converter.",
        "apihelp-expandtemplates-param-revid": "ID de revisión, para <nowiki>{{REVISIONID}}</nowiki> e variables similares.",
index 73b4420..72e6505 100644 (file)
        "apihelp-edit-param-tags": "אילו תגי שינוי להחיל על הגרסה.",
        "apihelp-edit-param-minor": "עריכה משנית.",
        "apihelp-edit-param-notminor": "שינוי לא משני.",
-       "apihelp-edit-param-bot": "סימון עריכה זו כבוט.",
+       "apihelp-edit-param-bot": "ס×\99×\9e×\95×\9f ×¢×¨×\99×\9b×\94 ×\96×\95 ×\9bער×\99×\9bת ×\91×\95×\98.",
        "apihelp-edit-param-basetimestamp": "חותם־זמן של גרסת הבסיס, משמש לזיהוי התנגשויות עריכה. אפשר לקבל אותו באמצעות [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "חותם־הזמן של תחילת תהליך העריכה, משמש לזיהוי התנגשויות. אפשר לקבל ערך מתאים באמצעות <var>[[Special:ApiHelp/main|curtimestamp]]</var> בעת תחילת תהליך העריכה (למשל בזמן טעינת תוכן הדף לעריכה).",
        "apihelp-edit-param-recreate": "לעקוב את כל הטעויות על כך שהדף נמחק בינתיים.",
        "apihelp-emailuser-param-text": "גוף הדואר.",
        "apihelp-emailuser-param-ccme": "שליחת עותק של הדואר הזה אליי.",
        "apihelp-emailuser-example-email": "שליחת דוא\"ל למשתמש <kbd>WikiSysop</kbd> עם הטקסט <kbd>Content</kbd>.",
-       "apihelp-expandtemplates-description": "הרחבת כל התבניות בקוד הוויקי.",
+       "apihelp-expandtemplates-description": "×\94ר×\97×\91ת ×\9b×\9c ×\94ת×\91× ×\99×\95ת ×\91ת×\95×\9a ×§×\95×\93 ×\94×\95×\95×\99ק×\99.",
        "apihelp-expandtemplates-param-title": "כותרת הדף.",
        "apihelp-expandtemplates-param-text": "איזה קוד ויקי להמיר.",
        "apihelp-expandtemplates-param-revid": "מזהה גרסה, עבור <nowiki>{{REVISIONID}}</nowiki> ומשתנים דומים.",
index 9786543..5f1d851 100644 (file)
@@ -90,7 +90,7 @@
        "apihelp-edit-param-tags": "Cambia i tag da applicare alla revisione.",
        "apihelp-edit-param-minor": "Modifica minore.",
        "apihelp-edit-param-notminor": "Modifica non minore.",
-       "apihelp-edit-param-bot": "Contrassegna questa modifica come bot.",
+       "apihelp-edit-param-bot": "Contrassegna questa modifica come eseguita da un bot.",
        "apihelp-edit-param-createonly": "Non modificare la pagina se già esiste.",
        "apihelp-edit-param-nocreate": "Genera un errore se la pagina non esiste.",
        "apihelp-edit-param-watch": "Aggiunge la pagina agli osservati speciali dell'utente attuale.",
        "apihelp-emailuser-param-text": "Testo dell'e-mail.",
        "apihelp-emailuser-param-ccme": "Mandami una copia di questa mail.",
        "apihelp-emailuser-example-email": "Manda una e-mail all'utente <kbd>WikiSysop</kbd> con il testo <kbd>Content</kbd>.",
-       "apihelp-expandtemplates-description": "Espandi tutti i template nel wikitesto.",
+       "apihelp-expandtemplates-description": "Espande tutti i template all'interno del wikitesto.",
        "apihelp-expandtemplates-param-title": "Titolo della pagina.",
        "apihelp-expandtemplates-param-text": "Wikitesto da convertire.",
        "apihelp-expandtemplates-param-prop": "Quale informazione ottenere.\n\nNota che se non è selezionato alcun valore, il risultato conterrà il codice wiki, ma l'output sarà in un formato obsoleto.",
index 5ae6c87..f15bec1 100644 (file)
@@ -88,7 +88,7 @@
        "apihelp-edit-param-tags": "이 판에 적용할 태그를 변경합니다.",
        "apihelp-edit-param-minor": "사소한 편집.",
        "apihelp-edit-param-notminor": "사소하지 않은 편집.",
-       "apihelp-edit-param-bot": "이 편집을 봇으로 표시.",
+       "apihelp-edit-param-bot": "이 편집을 봇 편집으로 표시.",
        "apihelp-edit-param-createonly": "이 페이지가 이미 존재하면 편집하지 않습니다.",
        "apihelp-edit-param-nocreate": "페이지가 존재하지 않으면 오류를 출력합니다.",
        "apihelp-edit-param-watch": "문서를 현재 사용자의 주시문서 목록에 추가합니다.",
        "apihelp-emailuser-param-text": "메일 본문.",
        "apihelp-emailuser-param-ccme": "자신에게 메일의 복사본을 보냅니다.",
        "apihelp-emailuser-example-email": "<kbd>WikiSysop</kbd> 사용자에게 텍스트 <kbd>Content</kbd>로 이메일을 보냅니다.",
-       "apihelp-expandtemplates-description": "모든 틀을 위키텍스트로 확장.",
+       "apihelp-expandtemplates-description": "위키텍스트 안에 모든 틀을 확장합니다.",
        "apihelp-expandtemplates-param-title": "문서 제목",
        "apihelp-expandtemplates-param-text": "변환할 위키텍스트.",
        "apihelp-expandtemplates-paramvalue-prop-wikitext": "확장된 위키텍스트.",
        "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "판의 콘텐츠 모델 ID.",
        "apihelp-query+revisions+base-paramvalue-prop-content": "판의 텍스트.",
        "apihelp-query+revisions+base-paramvalue-prop-tags": "판의 태그.",
+       "apihelp-query+search-description": "전문 검색을 수행합니다.",
        "apihelp-query+search-param-qiprofile": "쿼리 독립적인 프로파일 사용(순위 알고리즘에 영향있음)",
        "apihelp-query+search-paramvalue-prop-size": "바이트 단위로 문서의 크기를 추가합니다.",
        "apihelp-query+search-paramvalue-prop-wordcount": "문서의 낱말 수를 추가합니다.",
index a1e779a..47b79ab 100644 (file)
@@ -31,7 +31,7 @@
        "apihelp-edit-param-text": "Säiteninhalt.",
        "apihelp-edit-param-minor": "Kleng Ännerung.",
        "apihelp-edit-param-notminor": "Keng kleng Ännerung",
-       "apihelp-edit-param-bot": "Dës Ännerung als Bot-Ännerung markéieren.",
+       "apihelp-edit-param-bot": "Dës Ännerung als eng Bot-Ännerung markéieren.",
        "apihelp-edit-param-createonly": "D'Säit net ännere wann et se scho gëtt.",
        "apihelp-edit-param-watch": "D'Säit op dem aktuelle Benotzer seng Iwwerwaachungslëscht dobäisetzen.",
        "apihelp-edit-example-edit": "Eng Säit änneren",
index 03cb2b5..1580fcf 100644 (file)
        "apihelp-delete-description": "पान वगळा",
        "apihelp-edit-param-minor": "छोटे संपादन",
        "apihelp-edit-param-notminor": "छोटे नसलेले संपादन",
+       "apihelp-edit-param-bot": "या संपादनावर सांगकाम्याचे संपादन म्हणून खूण करा.",
        "apihelp-edit-example-edit": "पान संपादा",
+       "apihelp-expandtemplates-description": "विकिमजकूरात सर्व साच्यांचा विस्तार करा.",
+       "apihelp-feedcontributions-param-toponly": "केवळ नवीनतम आवर्तने असलेलीच संपादने दाखवा.",
        "apihelp-feedrecentchanges-param-categories": "या सर्व वर्गात असलेल्या पानांमधील बदलच फक्त  दाखवा.",
        "apihelp-feedrecentchanges-param-categories_any": "त्यापेक्षा,या कोणत्याही वर्गांमधील,पानांना झालेले बदलच फक्त दाखवा.",
        "apihelp-login-param-name": "सदस्य नाव.",
index c28ac64..fb6aed8 100644 (file)
        "apihelp-query+alldeletedrevisions-example-user": "Wymień ostatnie 50 usuniętych edycji przez użytkownika <kbd>Example</kbd>.",
        "apihelp-query+alldeletedrevisions-example-ns-main": "Wymień ostatnie 50 usuniętych edycji z przestrzeni głównej.",
        "apihelp-query+allfileusages-description": "Lista wykorzystania pliku, także dla nieistniejących.",
+       "apihelp-query+allfileusages-param-prop": "Jakie informacje dołączyć:",
        "apihelp-query+allfileusages-param-limit": "Łączna liczba obiektów do zwrócenia.",
        "apihelp-query+allfileusages-example-unique": "Lista unikatowych tytułów plików.",
        "apihelp-query+allimages-param-sort": "Sortowanie według właściwości.",
        "apihelp-query+allimages-example-recent": "Pokaż listę ostatnio przesłanych plików, podobnie do [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Pokaż listę plików z typem MIME <kbd>image/png</kbd> lub <kbd>image/gif</kbd>",
+       "apihelp-query+alllinks-param-prop": "Jakie informacje dołączyć:",
        "apihelp-query+alllinks-param-namespace": "Przestrzeń nazw do emulacji.",
        "apihelp-query+alllinks-param-limit": "Łączna liczba obiektów do zwrócenia.",
        "apihelp-query+alllinks-example-unique": "Lista unikatowych tytułów plików.",
        "apihelp-query+allpages-param-limit": "Liczba stron do zwrócenia.",
        "apihelp-query+allpages-example-B": "Pokaż listę stron rozpoczynających się na literę <kbd>B</kbd>.",
        "apihelp-query+allredirects-description": "Lista wszystkich przekierowań do przestrzeni nazw.",
+       "apihelp-query+allredirects-param-prop": "Jakie informacje dołączyć:",
        "apihelp-query+allredirects-param-namespace": "Przestrzeń nazw do emulacji.",
        "apihelp-query+allredirects-param-limit": "Łączna liczba obiektów do zwrócenia.",
        "apihelp-query+allrevisions-description": "Wyświetl wszystkie wersje.",
        "apihelp-query+allrevisions-param-excludeuser": "Nie wyświetlaj wersji tego użytkownika.",
        "apihelp-query+allrevisions-param-namespace": "Wyświetl tylko strony w przestrzeni głównej.",
        "apihelp-query+allrevisions-example-ns-main": "Wyświetl pierwsze 50 wersji w przestrzeni głównej.",
+       "apihelp-query+alltransclusions-param-prop": "Jakie informacje dołączyć:",
        "apihelp-query+alltransclusions-param-namespace": "Przestrzeń nazw do emulacji.",
+       "apihelp-query+allusers-param-dir": "Kierunek sortowania.",
+       "apihelp-query+allusers-param-prop": "Jakie informacje dołączyć:",
        "apihelp-query+allusers-param-witheditsonly": "Tylko użytkownicy, którzy edytowali.",
        "apihelp-query+backlinks-param-namespace": "Przestrzeń nazw do emulacji.",
        "apihelp-query+backlinks-example-simple": "Pokazuj linki do <kbd>Main page</kbd>.",
        "apihelp-query+duplicatefiles-example-generated": "Szukaj duplikatów wszystkich plików.",
        "apihelp-query+embeddedin-param-filterredir": "Jaki filtrować przekierowania.",
        "apihelp-query+extlinks-param-limit": "Liczba linków do zwrócenia.",
+       "apihelp-query+exturlusage-param-prop": "Jakie informacje dołączyć:",
        "apihelp-query+exturlusage-param-limit": "Liczba stron do zwrócenia.",
        "apihelp-query+filearchive-paramvalue-prop-dimensions": "Alias rozmiaru.",
        "apihelp-query+filearchive-example-simple": "Pokaż listę wszystkich usuniętych plików.",
        "apihelp-query+info-paramvalue-prop-readable": "Czy użytkownik może przeczytać tę stronę.",
        "apihelp-query+iwbacklinks-param-prefix": "Prefix interwiki.",
        "apihelp-query+iwbacklinks-param-limit": "Łączna liczba stron do zwrócenia.",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Dodaje prefiks interwiki.",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Dodaje tytuł interwiki.",
        "apihelp-query+iwlinks-paramvalue-prop-url": "Dodaje pełny adres URL.",
+       "apihelp-query+langlinks-paramvalue-prop-url": "Dodaje pełny adres URL.",
        "apihelp-query+links-param-limit": "Liczba linków do zwrócenia.",
        "apihelp-query+linkshere-paramvalue-prop-title": "Nazwa każdej strony.",
        "apihelp-query+linkshere-param-limit": "Liczba do zwrócenia.",
        "apihelp-query+logevents-description": "Pobierz eventy z logu.",
        "apihelp-query+logevents-example-simple": "Lista ostatnich zarejestrowanych zdarzeń.",
+       "apihelp-query+pageswithprop-param-prop": "Jakie informacje dołączyć:",
        "apihelp-query+pageswithprop-example-generator": "Pobierz dodatkowe informacje o pierwszych 10 stronach wykorzystując <code>_&#95;NOTOC_&#95;</code>.",
        "apihelp-query+prefixsearch-param-search": "Wyszukaj tekst.",
        "apihelp-query+prefixsearch-param-namespace": "Przestrzenie nazw do przeszukania.",
index a9fe784..1f1ac4b 100644 (file)
        "apihelp-emailuser-description": "Enviar correio eletrónico a utilizador.",
        "apihelp-emailuser-param-subject": "Assunto.",
        "apihelp-emailuser-param-text": "Texto.",
+       "apihelp-emailuser-param-ccme": "Enviar-me uma cópia desta mensagem de correio eletrónico.",
        "apihelp-expandtemplates-description": "Expande todas as predefinições em notação wiki.",
        "apihelp-expandtemplates-param-title": "Título da página.",
        "apihelp-expandtemplates-example-simple": "Expandir a notação wiki <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
        "apihelp-feedcontributions-param-feedformat": "O formato do feed.",
        "apihelp-feedcontributions-param-deletedonly": "Mostrar apenas contribuições eliminadas.",
+       "apihelp-feedcontributions-param-toponly": "Mostrar apenas as edições mais recentes.",
        "apihelp-feedcontributions-param-hideminor": "Ocultar edições menores.",
        "apihelp-feedcontributions-param-showsizediff": "Mostrar diferença de tamanho entre edições.",
        "apihelp-feedrecentchanges-param-feedformat": "O formato do feed.",
index 35389b0..e409591 100644 (file)
@@ -89,7 +89,7 @@
        "apihelp-edit-param-tags": "Ändra taggar till att gälla för revideringen.",
        "apihelp-edit-param-minor": "Mindre redigering.",
        "apihelp-edit-param-notminor": "Icke-mindre redigering.",
-       "apihelp-edit-param-bot": "Markera denna redigering som robotredigering.",
+       "apihelp-edit-param-bot": "Markera denna redigering som en robotredigering.",
        "apihelp-edit-param-basetimestamp": "Tidsstämpel för grundversionen, används för att upptäcka redigeringskonflikter. Kan erhållas genom [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
        "apihelp-edit-param-starttimestamp": "Tidsstämpel för när redigeringsprocessen började, används för att upptäcka redigeringskonflikter. Ett lämpligt värde kan erhållas via  <var>[[Special:ApiHelp/main|curtimestamp]]</var> när redigeringsprocessen startas (t.ex. när sidans innehåll laddas för redigering).",
        "apihelp-edit-param-recreate": "Ignorera felmeddelande om sidan har blivit raderad under tiden.",
        "apihelp-emailuser-param-text": "E-postmeddelandets innehåll.",
        "apihelp-emailuser-param-ccme": "Skicka en kopia av detta e-postmeddelande till mig.",
        "apihelp-emailuser-example-email": "Skicka ett e-postmeddelande till användaren <kbd>WikiSysop</kbd> med texten <kbd>Content</kbd>.",
-       "apihelp-expandtemplates-description": "Expanderar alla mallar i wikitext.",
+       "apihelp-expandtemplates-description": "Expanderar alla mallar inom wikitext.",
        "apihelp-expandtemplates-param-title": "Sidans rubrik.",
        "apihelp-expandtemplates-param-text": "Wikitext att konvertera.",
        "apihelp-expandtemplates-param-revid": "Revision ID, för <nowiki>{{REVISIONID}}</nowiki> och liknande variabler.",
index 4117204..bef2409 100644 (file)
@@ -21,7 +21,8 @@
                        "PhiLiP",
                        "Arthur2e5",
                        "損齋",
-                       "Myy730"
+                       "Myy730",
+                       "D41D8CD98F"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|文档]]\n* [[mw:API:FAQ|常见问题]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 邮件列表]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 程序错误与功能请求]\n</div>\n<strong>状态信息:</strong>本页所展示的所有特性都应正常工作,但是API仍在开发当中,将会随时变化。请订阅[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 邮件列表]以便获得更新通知。\n\n<strong>错误请求:</strong>当API收到错误请求时,HTTP header将会返回一个包含\"MediaWiki-API-Error\"的值,随后header的值与error code将会送回并设置为相同的值。详细信息请参阅[[mw:API:Errors_and_warnings|API: 错误与警告]]。\n\n<strong>测试中:</strong>测试API请求的易用性,请参见[[Special:ApiSandbox]]。",
        "apihelp-query+logevents-paramvalue-prop-ids": "添加日志活动的ID。",
        "apihelp-query+logevents-paramvalue-prop-title": "为日志事件添加页面标题。",
        "apihelp-query+logevents-paramvalue-prop-type": "添加日志活动的类型。",
-       "apihelp-query+logevents-paramvalue-prop-user": "为日志事件添加用户责任。",
-       "apihelp-query+logevents-paramvalue-prop-userid": "为日志事件添加对此负责的用户ID。",
+       "apihelp-query+logevents-paramvalue-prop-user": "添加对此日志事件负责的用户。",
+       "apihelp-query+logevents-paramvalue-prop-userid": "添加对此日志事件负责的用户的ID。",
        "apihelp-query+logevents-paramvalue-prop-timestamp": "为日志活动添加时间戳。",
        "apihelp-query+logevents-paramvalue-prop-comment": "添加日志活动的摘要。",
        "apihelp-query+logevents-paramvalue-prop-parsedcomment": "添加被解析的日志活动的摘要。",
        "apihelp-query+recentchanges-param-excludeuser": "不要列出此用户的更改。",
        "apihelp-query+recentchanges-param-tag": "只列出带此标签的更改。",
        "apihelp-query+recentchanges-param-prop": "包含的额外信息束:",
-       "apihelp-query+recentchanges-paramvalue-prop-user": "为编辑和标签添加用户责任,如果它们是IP的话。",
+       "apihelp-query+recentchanges-paramvalue-prop-user": "添加造成编辑的用户,并标出它们是否是IP。",
        "apihelp-query+recentchanges-paramvalue-prop-userid": "为编辑添加用户ID责任。",
        "apihelp-query+recentchanges-paramvalue-prop-comment": "为编辑添加摘要。",
        "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "为编辑添加解析的摘要。",
index eeb233e..d88a5b2 100644 (file)
@@ -2382,7 +2382,7 @@ class AuthManager implements LoggerAwareInterface {
                $session->set( 'AuthManager:lastAuthTimestamp', time() );
                $session->persist();
 
-               \ScopedCallback::consume( $delay );
+               \Wikimedia\ScopedCallback::consume( $delay );
 
                \Hooks::run( 'UserLoggedIn', [ $user ] );
        }
index b746fde..f676deb 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup Cache
  */
 use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
 
 /**
  * MediaWiki message cache structure version.
@@ -628,11 +629,11 @@ class MessageCache {
                if ( $dest === 'all' ) {
                        $cacheKey = wfMemcKey( 'messages', $code );
                        $success = $this->mMemc->set( $cacheKey, $cache );
+                       $this->setValidationHash( $code, $cache );
                } else {
                        $success = true;
                }
 
-               $this->setValidationHash( $code, $cache );
                $this->saveToLocalCache( $code, $cache );
 
                return $success;
index a8cad9f..ebedb7e 100644 (file)
@@ -25,6 +25,7 @@
 use Liuggio\StatsdClient\Factory\StatsdDataFactory;
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
 
 /**
  * Group all the pieces relevant to the context of a request into one instance
index 93b3ef6..6aa3831 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  */
 use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
 
 /**
  * Update object handling the cleanup of links tables after a page was deleted.
index 8954304..c7d378e 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
 
 /**
  * Class the manages updates of *_link tables as well as similar extension-managed tables
index cd644cb..16e9a44 100644 (file)
@@ -21,7 +21,7 @@
  * @ingroup DifferenceEngine
  */
 
-// Deprecated, use class constant instead
+/** @deprecated use class constant instead */
 define( 'MW_DIFF_VERSION', '1.11a' );
 
 /**
@@ -176,7 +176,7 @@ class DifferenceEngine extends ContextSource {
         *
         * @param int $id Revision ID
         *
-        * @return mixed URL or false
+        * @return string|bool Link HTML or false
         */
        public function deletedLink( $id ) {
                if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
index 4a1f190..736cb06 100644 (file)
@@ -87,7 +87,12 @@ class MWExceptionHandler {
         * @param Exception|Throwable $e
         */
        public static function rollbackMasterChangesAndLog( $e ) {
-               $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+               $services = MediaWikiServices::getInstance();
+               if ( $services->isServiceDisabled( 'DBLoadBalancerFactory' ) ) {
+                       return; // T147599
+               }
+
+               $lbFactory = $services->getDBLoadBalancerFactory();
                if ( $lbFactory->hasMasterChanges() ) {
                        $logger = LoggerFactory::getInstance( 'Bug56269' );
                        $logger->warning(
index c9fcb09..fee5d63 100644 (file)
@@ -120,6 +120,8 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable
         * @return OOUI\CheckboxMultiselectInputWidget
         */
        public function getInputOOUI( $value ) {
+               $this->mParent->getOutput()->addModules( 'oojs-ui-widgets' );
+
                $attr = $this->getTooltipAndAccessKey();
                $attr['id'] = $this->mID;
                $attr['name'] = "{$this->mName}[]";
index 33e1a1f..6dfa28b 100644 (file)
@@ -587,9 +587,7 @@ class PostgresInstaller extends DatabaseInstaller {
                        return $status;
                }
 
-               /**
-                * @var $conn Database
-                */
+               /** @var $conn DatabasePostgres */
                $conn = $status->value;
 
                if ( $conn->tableExists( 'archive' ) ) {
@@ -606,7 +604,7 @@ class PostgresInstaller extends DatabaseInstaller {
 
                        return $status;
                }
-               $error = $conn->sourceFile( $conn->getSchemaPath() );
+               $error = $conn->sourceFile( $this->getSchemaPath( $conn ) );
                if ( $error !== true ) {
                        $conn->reportQueryError( $error, 0, '', __METHOD__ );
                        $conn->rollback( __METHOD__ );
index 22cceb4..3660b82 100644 (file)
@@ -4,7 +4,8 @@
                        "Eitvys200",
                        "Mantak111",
                        "Zygimantus",
-                       "Hugo.arg"
+                       "Hugo.arg",
+                       "Homo"
                ]
        },
        "config-desc": "MediaWiki diegimas",
@@ -69,7 +70,7 @@
        "config-db-install-account": "Vartotojo paskyra diegimui",
        "config-db-username": "Duomenų bazės vartotojo vardas:",
        "config-db-password": "Duomenų bazės slaptažodis:",
-       "config-db-wiki-account": "Vartotojo paskyra normaliai operacijai",
+       "config-db-wiki-account": "Naudotojo paskyra įprastai operacijai",
        "config-db-prefix": "Duomenų bazės lentelės priešdėlis:",
        "config-mysql-old": "MySQL $1 ar vėlesnė yra reikalinga. Jūs turite $2.",
        "config-db-port": "Duomenų bazės prievadas:",
        "config-license": "Autorinės teisės ir licencija:",
        "config-license-pd": "Viešas domenas",
        "config-email-settings": "El. pašto nustatymai",
-       "config-email-watchlist": "Įjungti stebimų pranešimą",
+       "config-email-watchlist": "Įjungti stebimų pranešimą",
        "config-email-auth": "Įjungti el. pašto autentifikavimą",
        "config-upload-settings": "Vaizdų ir failų įkėlimai",
        "config-upload-enable": "Įgalinti failų įkėlimus",
index 856cdfd..aa01768 100644 (file)
@@ -21,6 +21,7 @@
  * @author Aaron Schulz
  */
 use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
 
 /**
  * Class to handle job queues stored in the DB
index 84ded8d..0469eeb 100644 (file)
@@ -26,6 +26,7 @@ use MediaWiki\Logger\LoggerFactory;
 use Liuggio\StatsdClient\Factory\StatsdDataFactory;
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
+use Wikimedia\ScopedCallback;
 
 /**
  * Job queue runner utility methods
index 060cabb..e2914be 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  * @ingroup Upload
  */
+use Wikimedia\ScopedCallback;
 
 /**
  * Assemble the segments of a chunked upload.
index 78531dc..37e80c2 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup Upload
  * @ingroup JobQueue
  */
+use Wikimedia\ScopedCallback;
 
 /**
  * Upload a file from the upload stash into the local file repo.
diff --git a/includes/libs/CryptHKDF.php b/includes/libs/CryptHKDF.php
new file mode 100644 (file)
index 0000000..4c86757
--- /dev/null
@@ -0,0 +1,282 @@
+<?php
+/**
+ * Extract-and-Expand Key Derivation Function (HKDF). A cryptographicly
+ * secure key expansion function based on RFC 5869.
+ *
+ * This relies on the secrecy of $wgSecretKey (by default), or $wgHKDFSecret.
+ * By default, sha256 is used as the underlying hashing algorithm, but any other
+ * algorithm can be used. Finding the secret key from the output would require
+ * an attacker to discover the input key (the PRK) to the hmac that generated
+ * the output, and discover the particular data, hmac'ed with an evolving key
+ * (salt), to produce the PRK. Even with md5, no publicly known attacks make
+ * this currently feasible.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @author Chris Steipp
+ * @file
+ */
+
+class CryptHKDF {
+
+       /**
+        * @var BagOStuff The persistent cache
+        */
+       protected $cache = null;
+
+       /**
+        * @var string Cache key we'll use for our salt
+        */
+       protected $cacheKey = null;
+
+       /**
+        * @var string The hash algorithm being used
+        */
+       protected $algorithm = null;
+
+       /**
+        * @var string binary string, the salt for the HKDF
+        * @see getSaltUsingCache
+        */
+       protected $salt = '';
+
+       /**
+        * @var string The pseudorandom key
+        */
+       private $prk = '';
+
+       /**
+        * The secret key material. This must be kept secret to preserve
+        * the security properties of this RNG.
+        *
+        * @var string
+        */
+       private $skm;
+
+       /**
+        * @var string The last block (K(i)) of the most recent expanded key
+        */
+       protected $lastK;
+
+       /**
+        * a "context information" string CTXinfo (which may be null)
+        * See http://eprint.iacr.org/2010/264.pdf Section 4.1
+        *
+        * @var array
+        */
+       protected $context = [];
+
+       /**
+        * Round count is computed based on the hash'es output length,
+        * which neither php nor openssl seem to provide easily.
+        *
+        * @var int[]
+        */
+       public static $hashLength = [
+               'md5' => 16,
+               'sha1' => 20,
+               'sha224' => 28,
+               'sha256' => 32,
+               'sha384' => 48,
+               'sha512' => 64,
+               'ripemd128' => 16,
+               'ripemd160' => 20,
+               'ripemd256' => 32,
+               'ripemd320' => 40,
+               'whirlpool' => 64,
+       ];
+
+       /**
+        * @var CryptRand
+        */
+       private $cryptRand;
+
+       /**
+        * @param string $secretKeyMaterial
+        * @param string $algorithm Name of hashing algorithm
+        * @param BagOStuff $cache
+        * @param string|array $context Context to mix into HKDF context
+        * @param CryptRand $cryptRand
+        * @throws InvalidArgumentException if secret key material is too short
+        */
+       public function __construct( $secretKeyMaterial, $algorithm, BagOStuff $cache, $context,
+               CryptRand $cryptRand
+       ) {
+               if ( strlen( $secretKeyMaterial ) < 16 ) {
+                       throw new InvalidArgumentException( "secret was too short." );
+               }
+               $this->skm = $secretKeyMaterial;
+               $this->algorithm = $algorithm;
+               $this->cache = $cache;
+               $this->context = is_array( $context ) ? $context : [ $context ];
+               $this->cryptRand = $cryptRand;
+
+               // To prevent every call from hitting the same memcache server, pick
+               // from a set of keys to use. mt_rand is only use to pick a random
+               // server, and does not affect the security of the process.
+               $this->cacheKey = $cache->makeKey( 'HKDF', mt_rand( 0, 16 ) );
+       }
+
+       /**
+        * Save the last block generated, so the next user will compute a different PRK
+        * from the same SKM. This should keep things unpredictable even if an attacker
+        * is able to influence CTXinfo.
+        */
+       function __destruct() {
+               if ( $this->lastK ) {
+                       $this->cache->set( $this->cacheKey, $this->lastK );
+               }
+       }
+
+       /**
+        * MW specific salt, cached from last run
+        * @return string Binary string
+        */
+       protected function getSaltUsingCache() {
+               if ( $this->salt == '' ) {
+                       $lastSalt = $this->cache->get( $this->cacheKey );
+                       if ( $lastSalt === false ) {
+                               // If we don't have a previous value to use as our salt, we use
+                               // 16 bytes from CryptRand, which will use a small amount of
+                               // entropy from our pool. Note, "XTR may be deterministic or keyed
+                               // via an optional “salt value”  (i.e., a non-secret random
+                               // value)..." - http://eprint.iacr.org/2010/264.pdf. However, we
+                               // use a strongly random value since we can.
+                               $lastSalt = $this->cryptRand->generate( 16 );
+                       }
+                       // Get a binary string that is hashLen long
+                       $this->salt = hash( $this->algorithm, $lastSalt, true );
+               }
+               return $this->salt;
+       }
+
+       /**
+        * Produce $bytes of secure random data. As a side-effect,
+        * $this->lastK is set to the last hashLen block of key material.
+        *
+        * @param int $bytes Number of bytes of data
+        * @param string $context Context to mix into CTXinfo
+        * @return string Binary string of length $bytes
+        */
+       public function generate( $bytes, $context = '' ) {
+               if ( $this->prk === '' ) {
+                       $salt = $this->getSaltUsingCache();
+                       $this->prk = self::HKDFExtract(
+                               $this->algorithm,
+                               $salt,
+                               $this->skm
+                       );
+               }
+
+               $CTXinfo = implode( ':', array_merge( $this->context, [ $context ] ) );
+
+               return self::HKDFExpand(
+                       $this->algorithm,
+                       $this->prk,
+                       $CTXinfo,
+                       $bytes,
+                       $this->lastK
+               );
+       }
+
+       /**
+        * RFC5869 defines HKDF in 2 steps, extraction and expansion.
+        * From http://eprint.iacr.org/2010/264.pdf:
+        *
+        * The scheme HKDF is specifed as:
+        *      HKDF(XTS, SKM, CTXinfo, L) = K(1) || K(2) || ... || K(t)
+        * where the values K(i) are defined as follows:
+        *      PRK = HMAC(XTS, SKM)
+        *      K(1) = HMAC(PRK, CTXinfo || 0);
+        *      K(i+1) = HMAC(PRK, K(i) || CTXinfo || i), 1 <= i < t;
+        * where t = [L/k] and the value K(t) is truncated to its first d = L mod k bits;
+        * the counter i is non-wrapping and of a given fixed size, e.g., a single byte.
+        * Note that the length of the HMAC output is the same as its key length and therefore
+        * the scheme is well defined.
+        *
+        * XTS is the "extractor salt"
+        * SKM is the "secret keying material"
+        *
+        * N.B. http://eprint.iacr.org/2010/264.pdf seems to differ from RFC 5869 in that the test
+        * vectors from RFC 5869 only work if K(0) = '' and K(1) = HMAC(PRK, K(0) || CTXinfo || 1)
+        *
+        * @param string $hash The hashing function to use (e.g., sha256)
+        * @param string $ikm The input keying material
+        * @param string $salt The salt to add to the ikm, to get the prk
+        * @param string $info Optional context (change the output without affecting
+        *      the randomness properties of the output)
+        * @param int $L Number of bytes to return
+        * @return string Cryptographically secure pseudorandom binary string
+        */
+       public static function HKDF( $hash, $ikm, $salt, $info, $L ) {
+               $prk = self::HKDFExtract( $hash, $salt, $ikm );
+               $okm = self::HKDFExpand( $hash, $prk, $info, $L );
+               return $okm;
+       }
+
+       /**
+        * Extract the PRK, PRK = HMAC(XTS, SKM)
+        * Note that the hmac is keyed with XTS (the salt),
+        * and the SKM (source key material) is the "data".
+        *
+        * @param string $hash The hashing function to use (e.g., sha256)
+        * @param string $salt The salt to add to the ikm, to get the prk
+        * @param string $ikm The input keying material
+        * @return string Binary string (pseudorandm key) used as input to HKDFExpand
+        */
+       private static function HKDFExtract( $hash, $salt, $ikm ) {
+               return hash_hmac( $hash, $ikm, $salt, true );
+       }
+
+       /**
+        * Expand the key with the given context
+        *
+        * @param string $hash Hashing Algorithm
+        * @param string $prk A pseudorandom key of at least HashLen octets
+        *    (usually, the output from the extract step)
+        * @param string $info Optional context and application specific information
+        *    (can be a zero-length string)
+        * @param int $bytes Length of output keying material in bytes
+        *    (<= 255*HashLen)
+        * @param string &$lastK Set by this function to the last block of the expansion.
+        *    In MediaWiki, this is used to seed future Extractions.
+        * @return string Cryptographically secure random string $bytes long
+        * @throws InvalidArgumentException
+        */
+       private static function HKDFExpand( $hash, $prk, $info, $bytes, &$lastK = '' ) {
+               $hashLen = self::$hashLength[$hash];
+               $rounds = ceil( $bytes / $hashLen );
+               $output = '';
+
+               if ( $bytes > 255 * $hashLen ) {
+                       throw new InvalidArgumentException( 'Too many bytes requested from HDKFExpand' );
+               }
+
+               // K(1) = HMAC(PRK, CTXinfo || 1);
+               // K(i) = HMAC(PRK, K(i-1) || CTXinfo || i); 1 < i <= t;
+               for ( $counter = 1; $counter <= $rounds; ++$counter ) {
+                       $lastK = hash_hmac(
+                               $hash,
+                               $lastK . $info . chr( $counter ),
+                               $prk,
+                               true
+                       );
+                       $output .= $lastK;
+               }
+
+               return substr( $output, 0, $bytes );
+       }
+}
diff --git a/includes/libs/IEContentAnalyzer.php b/includes/libs/IEContentAnalyzer.php
deleted file mode 100644 (file)
index 0d1e527..0000000
+++ /dev/null
@@ -1,851 +0,0 @@
-<?php
-/**
- * Simulation of Microsoft Internet Explorer's MIME type detection algorithm.
- *
- * @file
- * @todo Define the exact license of this file.
- */
-
-/**
- * This class simulates Microsoft Internet Explorer's terribly broken and
- * insecure MIME type detection algorithm. It can be used to check web uploads
- * with an apparently safe type, to see if IE will reinterpret them to produce
- * something dangerous.
- *
- * It is full of bugs and strange design choices should not under any
- * circumstances be used to determine a MIME type to present to a user or
- * client. (Apple Safari developers, this means you too.)
- *
- * This class is based on a disassembly of IE 5.0, 6.0 and 7.0. Although I have
- * attempted to ensure that this code works in exactly the same way as Internet
- * Explorer, it does not share any source code, or creative choices such as
- * variable names, thus I (Tim Starling) claim copyright on it.
- *
- * It may be redistributed without restriction. To aid reuse, this class does
- * not depend on any MediaWiki module.
- */
-class IEContentAnalyzer {
-       /**
-        * Relevant data taken from the type table in IE 5
-        */
-       protected $baseTypeTable = [
-               'ambiguous' /*1*/ => [
-                       'text/plain',
-                       'application/octet-stream',
-                       'application/x-netcdf', // [sic]
-               ],
-               'text' /*3*/ => [
-                       'text/richtext', 'image/x-bitmap', 'application/postscript', 'application/base64',
-                       'application/macbinhex40', 'application/x-cdf', 'text/scriptlet'
-               ],
-               'binary' /*4*/ => [
-                       'application/pdf', 'audio/x-aiff', 'audio/basic', 'audio/wav', 'image/gif',
-                       'image/pjpeg', 'image/jpeg', 'image/tiff', 'image/x-png', 'image/png', 'image/bmp',
-                       'image/x-jg', 'image/x-art', 'image/x-emf', 'image/x-wmf', 'video/avi',
-                       'video/x-msvideo', 'video/mpeg', 'application/x-compressed',
-                       'application/x-zip-compressed', 'application/x-gzip-compressed', 'application/java',
-                       'application/x-msdownload'
-               ],
-               'html' /*5*/ => [ 'text/html' ],
-       ];
-
-       /**
-        * Changes to the type table in later versions of IE
-        */
-       protected $addedTypes = [
-               'ie07' => [
-                       'text' => [ 'text/xml', 'application/xml' ]
-               ],
-       ];
-
-       /**
-        * An approximation of the "Content Type" values in HKEY_CLASSES_ROOT in a
-        * typical Windows installation.
-        *
-        * Used for extension to MIME type mapping if detection fails.
-        */
-       protected $registry = [
-               '.323' => 'text/h323',
-               '.3g2' => 'video/3gpp2',
-               '.3gp' => 'video/3gpp',
-               '.3gp2' => 'video/3gpp2',
-               '.3gpp' => 'video/3gpp',
-               '.aac' => 'audio/aac',
-               '.ac3' => 'audio/ac3',
-               '.accda' => 'application/msaccess',
-               '.accdb' => 'application/msaccess',
-               '.accdc' => 'application/msaccess',
-               '.accde' => 'application/msaccess',
-               '.accdr' => 'application/msaccess',
-               '.accdt' => 'application/msaccess',
-               '.ade' => 'application/msaccess',
-               '.adp' => 'application/msaccess',
-               '.adts' => 'audio/aac',
-               '.ai' => 'application/postscript',
-               '.aif' => 'audio/aiff',
-               '.aifc' => 'audio/aiff',
-               '.aiff' => 'audio/aiff',
-               '.amc' => 'application/x-mpeg',
-               '.application' => 'application/x-ms-application',
-               '.asf' => 'video/x-ms-asf',
-               '.asx' => 'video/x-ms-asf',
-               '.au' => 'audio/basic',
-               '.avi' => 'video/avi',
-               '.bmp' => 'image/bmp',
-               '.caf' => 'audio/x-caf',
-               '.cat' => 'application/vnd.ms-pki.seccat',
-               '.cbo' => 'application/sha',
-               '.cdda' => 'audio/aiff',
-               '.cer' => 'application/x-x509-ca-cert',
-               '.conf' => 'text/plain',
-               '.crl' => 'application/pkix-crl',
-               '.crt' => 'application/x-x509-ca-cert',
-               '.css' => 'text/css',
-               '.csv' => 'application/vnd.ms-excel',
-               '.der' => 'application/x-x509-ca-cert',
-               '.dib' => 'image/bmp',
-               '.dif' => 'video/x-dv',
-               '.dll' => 'application/x-msdownload',
-               '.doc' => 'application/msword',
-               '.docm' => 'application/vnd.ms-word.document.macroEnabled.12',
-               '.docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-               '.dot' => 'application/msword',
-               '.dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
-               '.dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
-               '.dv' => 'video/x-dv',
-               '.dwfx' => 'model/vnd.dwfx+xps',
-               '.edn' => 'application/vnd.adobe.edn',
-               '.eml' => 'message/rfc822',
-               '.eps' => 'application/postscript',
-               '.etd' => 'application/x-ebx',
-               '.exe' => 'application/x-msdownload',
-               '.fdf' => 'application/vnd.fdf',
-               '.fif' => 'application/fractals',
-               '.gif' => 'image/gif',
-               '.gsm' => 'audio/x-gsm',
-               '.hqx' => 'application/mac-binhex40',
-               '.hta' => 'application/hta',
-               '.htc' => 'text/x-component',
-               '.htm' => 'text/html',
-               '.html' => 'text/html',
-               '.htt' => 'text/webviewhtml',
-               '.hxa' => 'application/xml',
-               '.hxc' => 'application/xml',
-               '.hxd' => 'application/octet-stream',
-               '.hxe' => 'application/xml',
-               '.hxf' => 'application/xml',
-               '.hxh' => 'application/octet-stream',
-               '.hxi' => 'application/octet-stream',
-               '.hxk' => 'application/xml',
-               '.hxq' => 'application/octet-stream',
-               '.hxr' => 'application/octet-stream',
-               '.hxs' => 'application/octet-stream',
-               '.hxt' => 'application/xml',
-               '.hxv' => 'application/xml',
-               '.hxw' => 'application/octet-stream',
-               '.ico' => 'image/x-icon',
-               '.iii' => 'application/x-iphone',
-               '.ins' => 'application/x-internet-signup',
-               '.iqy' => 'text/x-ms-iqy',
-               '.isp' => 'application/x-internet-signup',
-               '.jfif' => 'image/jpeg',
-               '.jnlp' => 'application/x-java-jnlp-file',
-               '.jpe' => 'image/jpeg',
-               '.jpeg' => 'image/jpeg',
-               '.jpg' => 'image/jpeg',
-               '.jtx' => 'application/x-jtx+xps',
-               '.latex' => 'application/x-latex',
-               '.log' => 'text/plain',
-               '.m1v' => 'video/mpeg',
-               '.m2v' => 'video/mpeg',
-               '.m3u' => 'audio/x-mpegurl',
-               '.mac' => 'image/x-macpaint',
-               '.man' => 'application/x-troff-man',
-               '.mda' => 'application/msaccess',
-               '.mdb' => 'application/msaccess',
-               '.mde' => 'application/msaccess',
-               '.mfp' => 'application/x-shockwave-flash',
-               '.mht' => 'message/rfc822',
-               '.mhtml' => 'message/rfc822',
-               '.mid' => 'audio/mid',
-               '.midi' => 'audio/mid',
-               '.mod' => 'video/mpeg',
-               '.mov' => 'video/quicktime',
-               '.mp2' => 'video/mpeg',
-               '.mp2v' => 'video/mpeg',
-               '.mp3' => 'audio/mpeg',
-               '.mp4' => 'video/mp4',
-               '.mpa' => 'video/mpeg',
-               '.mpe' => 'video/mpeg',
-               '.mpeg' => 'video/mpeg',
-               '.mpf' => 'application/vnd.ms-mediapackage',
-               '.mpg' => 'video/mpeg',
-               '.mpv2' => 'video/mpeg',
-               '.mqv' => 'video/quicktime',
-               '.NMW' => 'application/nmwb',
-               '.nws' => 'message/rfc822',
-               '.odc' => 'text/x-ms-odc',
-               '.ols' => 'application/vnd.ms-publisher',
-               '.p10' => 'application/pkcs10',
-               '.p12' => 'application/x-pkcs12',
-               '.p7b' => 'application/x-pkcs7-certificates',
-               '.p7c' => 'application/pkcs7-mime',
-               '.p7m' => 'application/pkcs7-mime',
-               '.p7r' => 'application/x-pkcs7-certreqresp',
-               '.p7s' => 'application/pkcs7-signature',
-               '.pct' => 'image/pict',
-               '.pdf' => 'application/pdf',
-               '.pdx' => 'application/vnd.adobe.pdx',
-               '.pfx' => 'application/x-pkcs12',
-               '.pic' => 'image/pict',
-               '.pict' => 'image/pict',
-               '.pinstall' => 'application/x-picasa-detect',
-               '.pko' => 'application/vnd.ms-pki.pko',
-               '.png' => 'image/png',
-               '.pnt' => 'image/x-macpaint',
-               '.pntg' => 'image/x-macpaint',
-               '.pot' => 'application/vnd.ms-powerpoint',
-               '.potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
-               '.potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
-               '.ppa' => 'application/vnd.ms-powerpoint',
-               '.ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
-               '.pps' => 'application/vnd.ms-powerpoint',
-               '.ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
-               '.ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
-               '.ppt' => 'application/vnd.ms-powerpoint',
-               '.pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
-               '.pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
-               '.prf' => 'application/pics-rules',
-               '.ps' => 'application/postscript',
-               '.pub' => 'application/vnd.ms-publisher',
-               '.pwz' => 'application/vnd.ms-powerpoint',
-               '.py' => 'text/plain',
-               '.pyw' => 'text/plain',
-               '.qht' => 'text/x-html-insertion',
-               '.qhtm' => 'text/x-html-insertion',
-               '.qt' => 'video/quicktime',
-               '.qti' => 'image/x-quicktime',
-               '.qtif' => 'image/x-quicktime',
-               '.qtl' => 'application/x-quicktimeplayer',
-               '.rat' => 'application/rat-file',
-               '.rmf' => 'application/vnd.adobe.rmf',
-               '.rmi' => 'audio/mid',
-               '.rqy' => 'text/x-ms-rqy',
-               '.rtf' => 'application/msword',
-               '.sct' => 'text/scriptlet',
-               '.sd2' => 'audio/x-sd2',
-               '.sdp' => 'application/sdp',
-               '.shtml' => 'text/html',
-               '.sit' => 'application/x-stuffit',
-               '.sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
-               '.sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
-               '.slk' => 'application/vnd.ms-excel',
-               '.snd' => 'audio/basic',
-               '.so' => 'application/x-apachemodule',
-               '.sol' => 'text/plain',
-               '.sor' => 'text/plain',
-               '.spc' => 'application/x-pkcs7-certificates',
-               '.spl' => 'application/futuresplash',
-               '.sst' => 'application/vnd.ms-pki.certstore',
-               '.stl' => 'application/vnd.ms-pki.stl',
-               '.swf' => 'application/x-shockwave-flash',
-               '.thmx' => 'application/vnd.ms-officetheme',
-               '.tif' => 'image/tiff',
-               '.tiff' => 'image/tiff',
-               '.txt' => 'text/plain',
-               '.uls' => 'text/iuls',
-               '.vcf' => 'text/x-vcard',
-               '.vdx' => 'application/vnd.ms-visio.viewer',
-               '.vsd' => 'application/vnd.ms-visio.viewer',
-               '.vss' => 'application/vnd.ms-visio.viewer',
-               '.vst' => 'application/vnd.ms-visio.viewer',
-               '.vsx' => 'application/vnd.ms-visio.viewer',
-               '.vtx' => 'application/vnd.ms-visio.viewer',
-               '.wav' => 'audio/wav',
-               '.wax' => 'audio/x-ms-wax',
-               '.wbk' => 'application/msword',
-               '.wdp' => 'image/vnd.ms-photo',
-               '.wiz' => 'application/msword',
-               '.wm' => 'video/x-ms-wm',
-               '.wma' => 'audio/x-ms-wma',
-               '.wmd' => 'application/x-ms-wmd',
-               '.wmv' => 'video/x-ms-wmv',
-               '.wmx' => 'video/x-ms-wmx',
-               '.wmz' => 'application/x-ms-wmz',
-               '.wpl' => 'application/vnd.ms-wpl',
-               '.wsc' => 'text/scriptlet',
-               '.wvx' => 'video/x-ms-wvx',
-               '.xaml' => 'application/xaml+xml',
-               '.xbap' => 'application/x-ms-xbap',
-               '.xdp' => 'application/vnd.adobe.xdp+xml',
-               '.xfdf' => 'application/vnd.adobe.xfdf',
-               '.xht' => 'application/xhtml+xml',
-               '.xhtml' => 'application/xhtml+xml',
-               '.xla' => 'application/vnd.ms-excel',
-               '.xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
-               '.xlk' => 'application/vnd.ms-excel',
-               '.xll' => 'application/vnd.ms-excel',
-               '.xlm' => 'application/vnd.ms-excel',
-               '.xls' => 'application/vnd.ms-excel',
-               '.xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
-               '.xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
-               '.xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
-               '.xlt' => 'application/vnd.ms-excel',
-               '.xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
-               '.xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
-               '.xlw' => 'application/vnd.ms-excel',
-               '.xml' => 'text/xml',
-               '.xps' => 'application/vnd.ms-xpsdocument',
-               '.xsl' => 'text/xml',
-       ];
-
-       /**
-        * IE versions which have been analysed to bring you this class, and for
-        * which some substantive difference exists. These will appear as keys
-        * in the return value of getRealMimesFromData(). The names are chosen to sort correctly.
-        */
-       protected $versions = [ 'ie05', 'ie06', 'ie07', 'ie07.strict', 'ie07.nohtml' ];
-
-       /**
-        * Type table with versions expanded
-        */
-       protected $typeTable = [];
-
-       /** constructor */
-       function __construct() {
-               // Construct versioned type arrays from the base type array plus additions
-               $types = $this->baseTypeTable;
-               foreach ( $this->versions as $version ) {
-                       if ( isset( $this->addedTypes[$version] ) ) {
-                               foreach ( $this->addedTypes[$version] as $format => $addedTypes ) {
-                                       $types[$format] = array_merge( $types[$format], $addedTypes );
-                               }
-                       }
-                       $this->typeTable[$version] = $types;
-               }
-       }
-
-       /**
-        * Get the MIME types from getMimesFromData(), but convert the result from IE's
-        * idiosyncratic private types into something other apps will understand.
-        *
-        * @param string $fileName the file name (unused at present)
-        * @param string $chunk the first 256 bytes of the file
-        * @param string $proposed the MIME type proposed by the server
-        *
-        * @return Array: map of IE version to detected MIME type
-        */
-       public function getRealMimesFromData( $fileName, $chunk, $proposed ) {
-               $types = $this->getMimesFromData( $fileName, $chunk, $proposed );
-               $types = array_map( [ $this, 'translateMimeType' ], $types );
-               return $types;
-       }
-
-       /**
-        * Translate a MIME type from IE's idiosyncratic private types into
-        * more commonly understood type strings
-        * @param $type
-        * @return string
-        */
-       public function translateMimeType( $type ) {
-               static $table = [
-                       'image/pjpeg' => 'image/jpeg',
-                       'image/x-png' => 'image/png',
-                       'image/x-wmf' => 'application/x-msmetafile',
-                       'image/bmp' => 'image/x-bmp',
-                       'application/x-zip-compressed' => 'application/zip',
-                       'application/x-compressed' => 'application/x-compress',
-                       'application/x-gzip-compressed' => 'application/x-gzip',
-                       'audio/mid' => 'audio/midi',
-               ];
-               if ( isset( $table[$type] ) ) {
-                       $type = $table[$type];
-               }
-               return $type;
-       }
-
-       /**
-        * Get the untranslated MIME types for all known versions
-        *
-        * @param string $fileName the file name (unused at present)
-        * @param string $chunk the first 256 bytes of the file
-        * @param string $proposed the MIME type proposed by the server
-        *
-        * @return Array: map of IE version to detected MIME type
-        */
-       public function getMimesFromData( $fileName, $chunk, $proposed ) {
-               $types = [];
-               foreach ( $this->versions as $version ) {
-                       $types[$version] = $this->getMimeTypeForVersion( $version, $fileName, $chunk, $proposed );
-               }
-               return $types;
-       }
-
-       /**
-        * Get the MIME type for a given named version
-        * @param $version
-        * @param $fileName
-        * @param $chunk
-        * @param $proposed
-        * @return bool|string
-        */
-       protected function getMimeTypeForVersion( $version, $fileName, $chunk, $proposed ) {
-               // Strip text after a semicolon
-               $semiPos = strpos( $proposed, ';' );
-               if ( $semiPos !== false ) {
-                       $proposed = substr( $proposed, 0, $semiPos );
-               }
-
-               $proposedFormat = $this->getDataFormat( $version, $proposed );
-               if ( $proposedFormat == 'unknown'
-                       && $proposed != 'multipart/mixed'
-                       && $proposed != 'multipart/x-mixed-replace' )
-               {
-                       return $proposed;
-               }
-               if ( strval( $chunk ) === '' ) {
-                       return $proposed;
-               }
-
-               // Truncate chunk at 255 bytes
-               $chunk = substr( $chunk, 0, 255 );
-
-               // IE does the Check*Headers() calls last, and instead does the following image
-               // type checks by directly looking for the magic numbers. What I do here should
-               // have the same effect since the magic number checks are identical in both cases.
-               $result = $this->sampleData( $version, $chunk );
-               $sampleFound = $result['found'];
-               $counters = $result['counters'];
-               $binaryType = $this->checkBinaryHeaders( $version, $chunk );
-               $textType = $this->checkTextHeaders( $version, $chunk );
-
-               if ( $proposed == 'text/html' && isset( $sampleFound['html'] ) ) {
-                       return 'text/html';
-               }
-               if ( $proposed == 'image/gif' && $binaryType == 'image/gif' ) {
-                       return 'image/gif';
-               }
-               if ( ( $proposed == 'image/pjpeg' || $proposed == 'image/jpeg' )
-                       && $binaryType == 'image/pjpeg' )
-               {
-                       return $proposed;
-               }
-               // PNG check added in IE 7
-               if ( $version >= 'ie07'
-                       && ( $proposed == 'image/x-png' || $proposed == 'image/png' )
-                       && $binaryType == 'image/x-png' )
-               {
-                       return $proposed;
-               }
-
-               // CDF was removed in IE 7 so it won't be in $sampleFound for later versions
-               if ( isset( $sampleFound['cdf'] ) ) {
-                       return 'application/x-cdf';
-               }
-
-               // RSS and Atom were added in IE 7 so they won't be in $sampleFound for
-               // previous versions
-               if ( isset( $sampleFound['rss'] ) ) {
-                       return 'application/rss+xml';
-               }
-               if ( isset( $sampleFound['rdf-tag'] )
-                       && isset( $sampleFound['rdf-url'] )
-                       && isset( $sampleFound['rdf-purl'] ) )
-               {
-                       return 'application/rss+xml';
-               }
-               if ( isset( $sampleFound['atom'] ) ) {
-                       return 'application/atom+xml';
-               }
-
-               if ( isset( $sampleFound['xml'] ) ) {
-                       // TODO: I'm not sure under what circumstances this flag is enabled
-                       if ( strpos( $version, 'strict' ) !== false ) {
-                               if ( $proposed == 'text/html' || $proposed == 'text/xml' ) {
-                                       return 'text/xml';
-                               }
-                       } else {
-                               return 'text/xml';
-                       }
-               }
-               if ( isset( $sampleFound['html'] ) ) {
-                       // TODO: I'm not sure under what circumstances this flag is enabled
-                       if ( strpos( $version, 'nohtml' ) !== false ) {
-                               if ( $proposed == 'text/plain' ) {
-                                       return 'text/html';
-                               }
-                       } else {
-                               return 'text/html';
-                       }
-               }
-               if ( isset( $sampleFound['xbm'] ) ) {
-                       return 'image/x-bitmap';
-               }
-               if ( isset( $sampleFound['binhex'] ) ) {
-                       return 'application/macbinhex40';
-               }
-               if ( isset( $sampleFound['scriptlet'] ) ) {
-                       if ( strpos( $version, 'strict' ) !== false ) {
-                               if ( $proposed == 'text/plain' || $proposed == 'text/scriptlet' ) {
-                                       return 'text/scriptlet';
-                               }
-                       } else {
-                               return 'text/scriptlet';
-                       }
-               }
-
-               // Freaky heuristics to determine if the data is text or binary
-               // The heuristic is of course broken for non-ASCII text
-               if ( $counters['ctrl'] != 0 && ( $counters['ff'] + $counters['low'] )
-                       < ( $counters['ctrl'] + $counters['high'] ) * 16 )
-               {
-                       $kindOfBinary = true;
-                       $type = $binaryType ? $binaryType : $textType;
-                       if ( $type === false ) {
-                               $type = 'application/octet-stream';
-                       }
-               } else {
-                       $kindOfBinary = false;
-                       $type = $textType ? $textType : $binaryType;
-                       if ( $type === false ) {
-                               $type = 'text/plain';
-                       }
-               }
-
-               // Check if the output format is ambiguous
-               // This generally means that detection failed, real types aren't ambiguous
-               $detectedFormat = $this->getDataFormat( $version, $type );
-               if ( $detectedFormat != 'ambiguous' ) {
-                       return $type;
-               }
-
-               if ( $proposedFormat != 'ambiguous' ) {
-                       // FormatAgreesWithData()
-                       if ( $proposedFormat == 'text' && !$kindOfBinary ) {
-                               return $proposed;
-                       }
-                       if ( $proposedFormat == 'binary' && $kindOfBinary ) {
-                               return $proposed;
-                       }
-                       if ( $proposedFormat == 'html' ) {
-                               return $proposed;
-                       }
-               }
-
-               // Find a MIME type by searching the registry for the file extension.
-               $dotPos = strrpos( $fileName, '.' );
-               if ( $dotPos === false ) {
-                       return $type;
-               }
-               $ext = substr( $fileName, $dotPos );
-               if ( isset( $this->registry[$ext] ) ) {
-                       return $this->registry[$ext];
-               }
-
-               // TODO: If the extension has an application registered to it, IE will return
-               // application/octet-stream. We'll skip that, so we could erroneously
-               // return text/plain or application/x-netcdf where application/octet-stream
-               // would be correct.
-
-               return $type;
-       }
-
-       /**
-        * Check for text headers at the start of the chunk
-        * Confirmed same in 5 and 7.
-        * @param $version
-        * @param $chunk
-        * @return bool|string
-        */
-       private function checkTextHeaders( $version, $chunk ) {
-               $chunk2 = substr( $chunk, 0, 2 );
-               $chunk4 = substr( $chunk, 0, 4 );
-               $chunk5 = substr( $chunk, 0, 5 );
-               if ( $chunk4 == '%PDF' ) {
-                       return 'application/pdf';
-               }
-               if ( $chunk2 == '%!' ) {
-                       return 'application/postscript';
-               }
-               if ( $chunk5 == '{\\rtf' ) {
-                       return 'text/richtext';
-               }
-               if ( $chunk5 == 'begin' ) {
-                       return 'application/base64';
-               }
-               return false;
-       }
-
-       /**
-        * Check for binary headers at the start of the chunk
-        * Confirmed same in 5 and 7.
-        * @param $version
-        * @param $chunk
-        * @return bool|string
-        */
-       private function checkBinaryHeaders( $version, $chunk ) {
-               $chunk2 = substr( $chunk, 0, 2 );
-               $chunk3 = substr( $chunk, 0, 3 );
-               $chunk4 = substr( $chunk, 0, 4 );
-               $chunk5 = substr( $chunk, 0, 5 );
-               $chunk5uc = strtoupper( $chunk5 );
-               $chunk8 = substr( $chunk, 0, 8 );
-               if ( $chunk5uc == 'GIF87' || $chunk5uc == 'GIF89' ) {
-                       return 'image/gif';
-               }
-               if ( $chunk2 == "\xff\xd8" ) {
-                       return 'image/pjpeg'; // actually plain JPEG but this is what IE returns
-               }
-
-               if ( $chunk2 == 'BM'
-                       && substr( $chunk, 6, 2 ) == "\000\000"
-                       && substr( $chunk, 8, 2 ) == "\000\000" )
-               {
-                       return 'image/bmp'; // another non-standard MIME
-               }
-               if ( $chunk4 == 'RIFF'
-                       && substr( $chunk, 8, 4 ) == 'WAVE' )
-               {
-                       return 'audio/wav';
-               }
-               // These were integer literals in IE
-               // Perhaps the author was not sure what the target endianness was
-               if ( $chunk4 == ".sd\000"
-                       || $chunk4 == ".snd"
-                       || $chunk4 == "\000ds."
-                       || $chunk4 == "dns." )
-               {
-                       return 'audio/basic';
-               }
-               if ( $chunk3 == "MM\000" ) {
-                       return 'image/tiff';
-               }
-               if ( $chunk2 == 'MZ' ) {
-                       return 'application/x-msdownload';
-               }
-               if ( $chunk8 == "\x89PNG\x0d\x0a\x1a\x0a" ) {
-                       return 'image/x-png'; // [sic]
-               }
-               if ( strlen( $chunk ) >= 5 ) {
-                       $byte2 = ord( $chunk[2] );
-                       $byte4 = ord( $chunk[4] );
-                       if ( $byte2 >= 3 && $byte2 <= 31 && $byte4 == 0 && $chunk2 == 'JG' ) {
-                               return 'image/x-jg';
-                       }
-               }
-               // More endian confusion?
-               if ( $chunk4 == 'MROF' ) {
-                       return 'audio/x-aiff';
-               }
-               $chunk4_8 = substr( $chunk, 8, 4 );
-               if ( $chunk4 == 'FORM' && ( $chunk4_8 == 'AIFF' || $chunk4_8 == 'AIFC' ) ) {
-                       return 'audio/x-aiff';
-               }
-               if ( $chunk4 == 'RIFF' && $chunk4_8 == 'AVI ' ) {
-                       return 'video/avi';
-               }
-               if ( $chunk4 == "\x00\x00\x01\xb3" || $chunk4 == "\x00\x00\x01\xba" ) {
-                       return 'video/mpeg';
-               }
-               if ( $chunk4 == "\001\000\000\000"
-                       && substr( $chunk, 40, 4 ) == ' EMF' )
-               {
-                       return 'image/x-emf';
-               }
-               if ( $chunk4 == "\xd7\xcd\xc6\x9a" ) {
-                       return 'image/x-wmf';
-               }
-               if ( $chunk4 == "\xca\xfe\xba\xbe" ) {
-                       return 'application/java';
-               }
-               if ( $chunk2 == 'PK' ) {
-                       return 'application/x-zip-compressed';
-               }
-               if ( $chunk2 == "\x1f\x9d" ) {
-                       return 'application/x-compressed';
-               }
-               if ( $chunk2 == "\x1f\x8b" ) {
-                       return 'application/x-gzip-compressed';
-               }
-               // Skip redundant check for ZIP
-               if ( $chunk5 == "MThd\000" ) {
-                       return 'audio/mid';
-               }
-               if ( $chunk4 == '%PDF' ) {
-                       return 'application/pdf';
-               }
-               return false;
-       }
-
-       /**
-        * Do heuristic checks on the bulk of the data sample.
-        * Search for HTML tags.
-        * @param $version
-        * @param $chunk
-        * @return array
-        */
-       protected function sampleData( $version, $chunk ) {
-               $found = [];
-               $counters = [
-                       'ctrl' => 0,
-                       'high' => 0,
-                       'low' => 0,
-                       'lf' => 0,
-                       'cr' => 0,
-                       'ff' => 0
-               ];
-               $htmlTags = [
-                       'html',
-                       'head',
-                       'title',
-                       'body',
-                       'script',
-                       'a href',
-                       'pre',
-                       'img',
-                       'plaintext',
-                       'table'
-               ];
-               $rdfUrl = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
-               $rdfPurl = 'http://purl.org/rss/1.0/';
-               $xbmMagic1 = '#define';
-               $xbmMagic2 = '_width';
-               $xbmMagic3 = '_bits';
-               $binhexMagic = 'converted with BinHex';
-               $chunkLength = strlen( $chunk );
-
-               for ( $offset = 0; $offset < $chunkLength; $offset++ ) {
-                       $curChar = $chunk[$offset];
-                       if ( $curChar == "\x0a" ) {
-                               $counters['lf']++;
-                               continue;
-                       } elseif ( $curChar == "\x0d" ) {
-                               $counters['cr']++;
-                               continue;
-                       } elseif ( $curChar == "\x0c" ) {
-                               $counters['ff']++;
-                               continue;
-                       } elseif ( $curChar == "\t" ) {
-                               $counters['low']++;
-                               continue;
-                       } elseif ( ord( $curChar ) < 32 ) {
-                               $counters['ctrl']++;
-                               continue;
-                       } elseif ( ord( $curChar ) >= 128 ) {
-                               $counters['high']++;
-                               continue;
-                       }
-
-                       $counters['low']++;
-                       if ( $curChar == '<' ) {
-                               // XML
-                               $remainder = substr( $chunk, $offset + 1 );
-                               if ( !strncasecmp( $remainder, '?XML', 4 ) ) {
-                                       $nextChar = substr( $chunk, $offset + 5, 1 );
-                                       if ( $nextChar == ':' || $nextChar == ' ' || $nextChar == "\t" ) {
-                                               $found['xml'] = true;
-                                       }
-                               }
-                               // Scriptlet (JSP)
-                               if ( !strncasecmp( $remainder, 'SCRIPTLET', 9 ) ) {
-                                       $found['scriptlet'] = true;
-                                       break;
-                               }
-                               // HTML
-                               foreach ( $htmlTags as $tag ) {
-                                       if ( !strncasecmp( $remainder, $tag, strlen( $tag ) ) ) {
-                                               $found['html'] = true;
-                                       }
-                               }
-                               // Skip broken check for additional tags (HR etc.)
-
-                               // CHANNEL replaced by RSS, RDF and FEED in IE 7
-                               if ( $version < 'ie07' ) {
-                                       if ( !strncasecmp( $remainder, 'CHANNEL', 7 ) ) {
-                                               $found['cdf'] = true;
-                                       }
-                               } else {
-                                       // RSS
-                                       if ( !strncasecmp( $remainder, 'RSS', 3 ) ) {
-                                               $found['rss'] = true;
-                                               break; // return from SampleData
-                                       }
-                                       if ( !strncasecmp( $remainder, 'rdf:RDF', 7 ) ) {
-                                               $found['rdf-tag'] = true;
-                                               // no break
-                                       }
-                                       if ( !strncasecmp( $remainder, 'FEED', 4 ) ) {
-                                               $found['atom'] = true;
-                                               break;
-                                       }
-                               }
-                               continue;
-                       }
-                       // Skip broken check for -->
-
-                       // RSS URL checks
-                       // For some reason both URLs must appear before it is recognised
-                       $remainder = substr( $chunk, $offset );
-                       if ( !strncasecmp( $remainder, $rdfUrl, strlen( $rdfUrl ) ) ) {
-                               $found['rdf-url'] = true;
-                               if ( isset( $found['rdf-tag'] )
-                                       && isset( $found['rdf-purl'] ) ) // [sic]
-                               {
-                                       break;
-                               }
-                               continue;
-                       }
-
-                       if ( !strncasecmp( $remainder, $rdfPurl, strlen( $rdfPurl ) ) ) {
-                               if ( isset( $found['rdf-tag'] )
-                                       && isset( $found['rdf-url'] ) ) // [sic]
-                               {
-                                       break;
-                               }
-                               continue;
-                       }
-
-                       // XBM checks
-                       if ( !strncasecmp( $remainder, $xbmMagic1, strlen( $xbmMagic1 ) ) ) {
-                               $found['xbm1'] = true;
-                               continue;
-                       }
-                       if ( $curChar == '_' ) {
-                               if ( isset( $found['xbm2'] ) ) {
-                                       if ( !strncasecmp( $remainder, $xbmMagic3, strlen( $xbmMagic3 ) ) ) {
-                                               $found['xbm'] = true;
-                                               break;
-                                       }
-                               } elseif ( isset( $found['xbm1'] ) ) {
-                                       if ( !strncasecmp( $remainder, $xbmMagic2, strlen( $xbmMagic2 ) ) ) {
-                                               $found['xbm2'] = true;
-                                       }
-                               }
-                       }
-
-                       // BinHex
-                       if ( !strncmp( $remainder, $binhexMagic, strlen( $binhexMagic ) ) ) {
-                               $found['binhex'] = true;
-                       }
-               }
-               return [ 'found' => $found, 'counters' => $counters ];
-       }
-
-       /**
-        * @param $version
-        * @param $type
-        * @return int|string
-        */
-       protected function getDataFormat( $version, $type ) {
-               $types = $this->typeTable[$version];
-               if ( $type == '(null)' || strval( $type ) === '' ) {
-                       return 'ambiguous';
-               }
-               foreach ( $types as $format => $list ) {
-                       if ( in_array( $type, $list ) ) {
-                               return $format;
-                       }
-               }
-               return 'unknown';
-       }
-}
diff --git a/includes/libs/XmlTypeCheck.php b/includes/libs/XmlTypeCheck.php
deleted file mode 100644 (file)
index f057140..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-<?php
-/**
- * XML syntax and type checker.
- *
- * Since 1.24.2, it uses XMLReader instead of xml_parse, which gives us
- * more control over the expansion of XML entities. When passed to the
- * callback, entities will be fully expanded, but may report the XML is
- * invalid if expanding the entities are likely to cause a DoS.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-class XmlTypeCheck {
-       /**
-        * Will be set to true or false to indicate whether the file is
-        * well-formed XML. Note that this doesn't check schema validity.
-        */
-       public $wellFormed = null;
-
-       /**
-        * Will be set to true if the optional element filter returned
-        * a match at some point.
-        */
-       public $filterMatch = false;
-
-       /**
-        * Will contain the type of filter hit if the optional element filter returned
-        * a match at some point.
-        * @var mixed
-        */
-       public $filterMatchType = false;
-
-       /**
-        * Name of the document's root element, including any namespace
-        * as an expanded URL.
-        */
-       public $rootElement = '';
-
-       /**
-        * A stack of strings containing the data of each xml element as it's processed. Append
-        * data to the top string of the stack, then pop off the string and process it when the
-        * element is closed.
-        */
-       protected $elementData = [];
-
-       /**
-        * A stack of element names and attributes, as we process them.
-        */
-       protected $elementDataContext = [];
-
-       /**
-        * Current depth of the data stack.
-        */
-       protected $stackDepth = 0;
-
-       /**
-        * Additional parsing options
-        */
-       private $parserOptions = [
-               'processing_instruction_handler' => '',
-       ];
-
-       /**
-        * @param string $input a filename or string containing the XML element
-        * @param callable $filterCallback (optional)
-        *        Function to call to do additional custom validity checks from the
-        *        SAX element handler event. This gives you access to the element
-        *        namespace, name, attributes, and text contents.
-        *        Filter should return 'true' to toggle on $this->filterMatch
-        * @param bool $isFile (optional) indicates if the first parameter is a
-        *        filename (default, true) or if it is a string (false)
-        * @param array $options list of additional parsing options:
-        *        processing_instruction_handler: Callback for xml_set_processing_instruction_handler
-        */
-       function __construct( $input, $filterCallback = null, $isFile = true, $options = [] ) {
-               $this->filterCallback = $filterCallback;
-               $this->parserOptions = array_merge( $this->parserOptions, $options );
-               $this->validateFromInput( $input, $isFile );
-       }
-
-       /**
-        * Alternative constructor: from filename
-        *
-        * @param string $fname the filename of an XML document
-        * @param callable $filterCallback (optional)
-        *        Function to call to do additional custom validity checks from the
-        *        SAX element handler event. This gives you access to the element
-        *        namespace, name, and attributes, but not to text contents.
-        *        Filter should return 'true' to toggle on $this->filterMatch
-        * @return XmlTypeCheck
-        */
-       public static function newFromFilename( $fname, $filterCallback = null ) {
-               return new self( $fname, $filterCallback, true );
-       }
-
-       /**
-        * Alternative constructor: from string
-        *
-        * @param string $string a string containing an XML element
-        * @param callable $filterCallback (optional)
-        *        Function to call to do additional custom validity checks from the
-        *        SAX element handler event. This gives you access to the element
-        *        namespace, name, and attributes, but not to text contents.
-        *        Filter should return 'true' to toggle on $this->filterMatch
-        * @return XmlTypeCheck
-        */
-       public static function newFromString( $string, $filterCallback = null ) {
-               return new self( $string, $filterCallback, false );
-       }
-
-       /**
-        * Get the root element. Simple accessor to $rootElement
-        *
-        * @return string
-        */
-       public function getRootElement() {
-               return $this->rootElement;
-       }
-
-       /**
-        * @param string $fname the filename
-        */
-       private function validateFromInput( $xml, $isFile ) {
-               $reader = new XMLReader();
-               if ( $isFile ) {
-                       $s = $reader->open( $xml, null, LIBXML_NOERROR | LIBXML_NOWARNING );
-               } else {
-                       $s = $reader->XML( $xml, null, LIBXML_NOERROR | LIBXML_NOWARNING );
-               }
-               if ( $s !== true ) {
-                       // Couldn't open the XML
-                       $this->wellFormed = false;
-               } else {
-                       $oldDisable = libxml_disable_entity_loader( true );
-                       $reader->setParserProperty( XMLReader::SUBST_ENTITIES, true );
-                       try {
-                               $this->validate( $reader );
-                       } catch ( Exception $e ) {
-                               // Calling this malformed, because we didn't parse the whole
-                               // thing. Maybe just an external entity refernce.
-                               $this->wellFormed = false;
-                               $reader->close();
-                               libxml_disable_entity_loader( $oldDisable );
-                               throw $e;
-                       }
-                       $reader->close();
-                       libxml_disable_entity_loader( $oldDisable );
-               }
-       }
-
-       private function readNext( XMLReader $reader ) {
-               set_error_handler( [ $this, 'XmlErrorHandler' ] );
-               $ret = $reader->read();
-               restore_error_handler();
-               return $ret;
-       }
-
-       public function XmlErrorHandler( $errno, $errstr ) {
-               $this->wellFormed = false;
-       }
-
-       private function validate( $reader ) {
-
-               // First, move through anything that isn't an element, and
-               // handle any processing instructions with the callback
-               do {
-                       if ( !$this->readNext( $reader ) ) {
-                               // Hit the end of the document before any elements
-                               $this->wellFormed = false;
-                               return;
-                       }
-                       if ( $reader->nodeType === XMLReader::PI ) {
-                               $this->processingInstructionHandler( $reader->name, $reader->value );
-                       }
-               } while ( $reader->nodeType != XMLReader::ELEMENT );
-
-               // Process the rest of the document
-               do {
-                       switch ( $reader->nodeType ) {
-                               case XMLReader::ELEMENT:
-                                       $name = $this->expandNS(
-                                               $reader->name,
-                                               $reader->namespaceURI
-                                       );
-                                       if ( $this->rootElement === '' ) {
-                                               $this->rootElement = $name;
-                                       }
-                                       $empty = $reader->isEmptyElement;
-                                       $attrs = $this->getAttributesArray( $reader );
-                                       $this->elementOpen( $name, $attrs );
-                                       if ( $empty ) {
-                                               $this->elementClose();
-                                       }
-                                       break;
-
-                               case XMLReader::END_ELEMENT:
-                                       $this->elementClose();
-                                       break;
-
-                               case XMLReader::WHITESPACE:
-                               case XMLReader::SIGNIFICANT_WHITESPACE:
-                               case XMLReader::CDATA:
-                               case XMLReader::TEXT:
-                                       $this->elementData( $reader->value );
-                                       break;
-
-                               case XMLReader::ENTITY_REF:
-                                       // Unexpanded entity (maybe external?),
-                                       // don't send to the filter (xml_parse didn't)
-                                       break;
-
-                               case XMLReader::COMMENT:
-                                       // Don't send to the filter (xml_parse didn't)
-                                       break;
-
-                               case XMLReader::PI:
-                                       // Processing instructions can happen after the header too
-                                       $this->processingInstructionHandler(
-                                               $reader->name,
-                                               $reader->value
-                                       );
-                                       break;
-                               default:
-                                       // One of DOC, DOC_TYPE, ENTITY, END_ENTITY,
-                                       // NOTATION, or XML_DECLARATION
-                                       // xml_parse didn't send these to the filter, so we won't.
-                       }
-
-               } while ( $this->readNext( $reader ) );
-
-               if ( $this->stackDepth !== 0 ) {
-                       $this->wellFormed = false;
-               } elseif ( $this->wellFormed === null ) {
-                       $this->wellFormed = true;
-               }
-
-       }
-
-       /**
-        * Get all of the attributes for an XMLReader's current node
-        * @param $r XMLReader
-        * @return array of attributes
-        */
-       private function getAttributesArray( XMLReader $r ) {
-               $attrs = [];
-               while ( $r->moveToNextAttribute() ) {
-                       if ( $r->namespaceURI === 'http://www.w3.org/2000/xmlns/' ) {
-                               // XMLReader treats xmlns attributes as normal
-                               // attributes, while xml_parse doesn't
-                               continue;
-                       }
-                       $name = $this->expandNS( $r->name, $r->namespaceURI );
-                       $attrs[$name] = $r->value;
-               }
-               return $attrs;
-       }
-
-       /**
-        * @param $name element or attribute name, maybe with a full or short prefix
-        * @param $namespaceURI the namespaceURI
-        * @return string the name prefixed with namespaceURI
-        */
-       private function expandNS( $name, $namespaceURI ) {
-               if ( $namespaceURI ) {
-                       $parts = explode( ':', $name );
-                       $localname = array_pop( $parts );
-                       return "$namespaceURI:$localname";
-               }
-               return $name;
-       }
-
-       /**
-        * @param $name
-        * @param $attribs
-        */
-       private function elementOpen( $name, $attribs ) {
-               $this->elementDataContext[] = [ $name, $attribs ];
-               $this->elementData[] = '';
-               $this->stackDepth++;
-       }
-
-       /**
-        */
-       private function elementClose() {
-               list( $name, $attribs ) = array_pop( $this->elementDataContext );
-               $data = array_pop( $this->elementData );
-               $this->stackDepth--;
-               $callbackReturn = false;
-
-               if ( is_callable( $this->filterCallback ) ) {
-                       $callbackReturn = call_user_func(
-                               $this->filterCallback,
-                               $name,
-                               $attribs,
-                               $data
-                       );
-               }
-               if ( $callbackReturn ) {
-                       // Filter hit!
-                       $this->filterMatch = true;
-                       $this->filterMatchType = $callbackReturn;
-               }
-       }
-
-       /**
-        * @param $data
-        */
-       private function elementData( $data ) {
-               // Collect any data here, and we'll run the callback in elementClose
-               $this->elementData[ $this->stackDepth - 1 ] .= trim( $data );
-       }
-
-       /**
-        * @param $target
-        * @param $data
-        */
-       private function processingInstructionHandler( $target, $data ) {
-               $callbackReturn = false;
-               if ( $this->parserOptions['processing_instruction_handler'] ) {
-                       $callbackReturn = call_user_func(
-                               $this->parserOptions['processing_instruction_handler'],
-                               $target,
-                               $data
-                       );
-               }
-               if ( $callbackReturn ) {
-                       // Filter hit!
-                       $this->filterMatch = true;
-                       $this->filterMatchType = $callbackReturn;
-               }
-       }
-}
index 311508f..62231a8 100644 (file)
@@ -12,14 +12,9 @@ class ComposerJson {
         * @param string $location
         */
        public function __construct( $location ) {
-               $this->hash = md5_file( $location );
                $this->contents = json_decode( file_get_contents( $location ), true );
        }
 
-       public function getHash() {
-               return $this->hash;
-       }
-
        /**
         * Dependencies as specified by composer.json
         *
index e93127c..818ccdf 100644 (file)
@@ -15,10 +15,6 @@ class ComposerLock {
                $this->contents = json_decode( file_get_contents( $location ), true );
        }
 
-       public function getHash() {
-               return $this->contents['hash'];
-       }
-
        /**
         * Dependencies currently installed according to composer.lock
         *
diff --git a/includes/libs/filebackend/FSFile.php b/includes/libs/filebackend/FSFile.php
deleted file mode 100644 (file)
index dacad1c..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-<?php
-/**
- * Non-directory file on the file system.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup FileBackend
- */
-
-/**
- * Class representing a non-directory file on the file system
- *
- * @ingroup FileBackend
- */
-class FSFile {
-       /** @var string Path to file */
-       protected $path;
-
-       /** @var string File SHA-1 in base 36 */
-       protected $sha1Base36;
-
-       /**
-        * Sets up the file object
-        *
-        * @param string $path Path to temporary file on local disk
-        */
-       public function __construct( $path ) {
-               $this->path = $path;
-       }
-
-       /**
-        * Returns the file system path
-        *
-        * @return string
-        */
-       public function getPath() {
-               return $this->path;
-       }
-
-       /**
-        * Checks if the file exists
-        *
-        * @return bool
-        */
-       public function exists() {
-               return is_file( $this->path );
-       }
-
-       /**
-        * Get the file size in bytes
-        *
-        * @return int|bool
-        */
-       public function getSize() {
-               return filesize( $this->path );
-       }
-
-       /**
-        * Get the file's last-modified timestamp
-        *
-        * @return string|bool TS_MW timestamp or false on failure
-        */
-       public function getTimestamp() {
-               MediaWiki\suppressWarnings();
-               $timestamp = filemtime( $this->path );
-               MediaWiki\restoreWarnings();
-               if ( $timestamp !== false ) {
-                       $timestamp = wfTimestamp( TS_MW, $timestamp );
-               }
-
-               return $timestamp;
-       }
-
-       /**
-        * Get an associative array containing information about
-        * a file with the given storage path.
-        *
-        * Resulting array fields include:
-        *   - fileExists
-        *   - size (filesize in bytes)
-        *   - mime (as major/minor)
-        *   - file-mime (as major/minor)
-        *   - sha1 (in base 36)
-        *   - major_mime
-        *   - minor_mime
-        *
-        * @param string|bool $ext The file extension, or true to extract it from the filename.
-        *             Set it to false to ignore the extension. Currently unused.
-        * @return array
-        */
-       public function getProps( $ext = true ) {
-               $info = self::placeholderProps();
-               $info['fileExists'] = $this->exists();
-
-               if ( $info['fileExists'] ) {
-                       $info['size'] = $this->getSize(); // bytes
-                       $info['sha1'] = $this->getSha1Base36();
-
-                       $mime = mime_content_type( $this->path );
-                       # MIME type according to file contents
-                       $info['file-mime'] = ( $mime === false ) ? 'unknown/unknown' : $mime;
-                       # logical MIME type
-                       $info['mime'] = $mime;
-
-                       if ( strpos( $mime, '/' ) !== false ) {
-                               list( $info['major_mime'], $info['minor_mime'] ) = explode( '/', $mime, 2 );
-                       } else {
-                               list( $info['major_mime'], $info['minor_mime'] ) = [ $mime, 'unknown' ];
-                       }
-               }
-
-               return $info;
-       }
-
-       /**
-        * Placeholder file properties to use for files that don't exist
-        *
-        * Resulting array fields include:
-        *   - fileExists
-        *   - size (filesize in bytes)
-        *   - mime (as major/minor)
-        *   - file-mime (as major/minor)
-        *   - sha1 (in base 36)
-        *   - major_mime
-        *   - minor_mime
-        *
-        * @return array
-        */
-       public static function placeholderProps() {
-               $info = [];
-               $info['fileExists'] = false;
-               $info['size'] = 0;
-               $info['file-mime'] = null;
-               $info['major_mime'] = null;
-               $info['minor_mime'] = null;
-               $info['mime'] = null;
-               $info['sha1'] = '';
-
-               return $info;
-       }
-
-       /**
-        * Get a SHA-1 hash of a file in the local filesystem, in base-36 lower case
-        * encoding, zero padded to 31 digits.
-        *
-        * 160 log 2 / log 36 = 30.95, so the 160-bit hash fills 31 digits in base 36
-        * fairly neatly.
-        *
-        * @param bool $recache
-        * @return bool|string False on failure
-        */
-       public function getSha1Base36( $recache = false ) {
-               if ( $this->sha1Base36 !== null && !$recache ) {
-                       return $this->sha1Base36;
-               }
-
-               MediaWiki\suppressWarnings();
-               $this->sha1Base36 = sha1_file( $this->path );
-               MediaWiki\restoreWarnings();
-
-               if ( $this->sha1Base36 !== false ) {
-                       $this->sha1Base36 = Wikimedia\base_convert( $this->sha1Base36, 16, 36, 31 );
-               }
-
-               return $this->sha1Base36;
-       }
-
-       /**
-        * Get the final file extension from a file system path
-        *
-        * @param string $path
-        * @return string
-        */
-       public static function extensionFromPath( $path ) {
-               $i = strrpos( $path, '.' );
-
-               return strtolower( $i ? substr( $path, $i + 1 ) : '' );
-       }
-
-       /**
-        * Get an associative array containing information about a file in the local filesystem.
-        *
-        * @param string $path Absolute local filesystem path
-        * @param string|bool $ext The file extension, or true to extract it from the filename.
-        *   Set it to false to ignore the extension.
-        * @return array
-        */
-       public static function getPropsFromPath( $path, $ext = true ) {
-               $fsFile = new self( $path );
-
-               return $fsFile->getProps( $ext );
-       }
-
-       /**
-        * Get a SHA-1 hash of a file in the local filesystem, in base-36 lower case
-        * encoding, zero padded to 31 digits.
-        *
-        * 160 log 2 / log 36 = 30.95, so the 160-bit hash fills 31 digits in base 36
-        * fairly neatly.
-        *
-        * @param string $path
-        * @return bool|string False on failure
-        */
-       public static function getSha1Base36FromPath( $path ) {
-               $fsFile = new self( $path );
-
-               return $fsFile->getSha1Base36();
-       }
-}
index f33f522..5764cc3 100644 (file)
@@ -30,6 +30,7 @@
  */
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
+use Wikimedia\ScopedCallback;
 
 /**
  * @brief Base class for all file backend classes (including multi-write backends).
diff --git a/includes/libs/filebackend/TempFSFile.php b/includes/libs/filebackend/TempFSFile.php
deleted file mode 100644 (file)
index fed6812..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-<?php
-/**
- * Location holder of files stored temporarily
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup FileBackend
- */
-
-/**
- * This class is used to hold the location and do limited manipulation
- * of files stored temporarily (this will be whatever wfTempDir() returns)
- *
- * @ingroup FileBackend
- */
-class TempFSFile extends FSFile {
-       /** @var bool Garbage collect the temp file */
-       protected $canDelete = false;
-
-       /** @var array Map of (path => 1) for paths to delete on shutdown */
-       protected static $pathsCollect = null;
-
-       public function __construct( $path ) {
-               parent::__construct( $path );
-
-               if ( self::$pathsCollect === null ) {
-                       self::$pathsCollect = [];
-                       register_shutdown_function( [ __CLASS__, 'purgeAllOnShutdown' ] );
-               }
-       }
-
-       /**
-        * Make a new temporary file on the file system.
-        * Temporary files may be purged when the file object falls out of scope.
-        *
-        * @param string $prefix
-        * @param string $extension Optional file extension
-        * @param string|null $tmpDirectory Optional parent directory
-        * @return TempFSFile|null
-        */
-       public static function factory( $prefix, $extension = '', $tmpDirectory = null ) {
-               $ext = ( $extension != '' ) ? ".{$extension}" : '';
-
-               $attempts = 5;
-               while ( $attempts-- ) {
-                       $hex = sprintf( '%06x%06x', mt_rand( 0, 0xffffff ), mt_rand( 0, 0xffffff ) );
-                       if ( !is_string( $tmpDirectory ) ) {
-                               $tmpDirectory = self::getUsableTempDirectory();
-                       }
-                       $path = wfTempDir() . '/' . $prefix . $hex . $ext;
-                       MediaWiki\suppressWarnings();
-                       $newFileHandle = fopen( $path, 'x' );
-                       MediaWiki\restoreWarnings();
-                       if ( $newFileHandle ) {
-                               fclose( $newFileHandle );
-                               $tmpFile = new self( $path );
-                               $tmpFile->autocollect();
-                               // Safely instantiated, end loop.
-                               return $tmpFile;
-                       }
-               }
-
-               // Give up
-               return null;
-       }
-
-       /**
-        * @return string Filesystem path to a temporary directory
-        * @throws RuntimeException
-        */
-       public static function getUsableTempDirectory() {
-               $tmpDir = array_map( 'getenv', [ 'TMPDIR', 'TMP', 'TEMP' ] );
-               $tmpDir[] = sys_get_temp_dir();
-               $tmpDir[] = ini_get( 'upload_tmp_dir' );
-               foreach ( $tmpDir as $tmp ) {
-                       if ( $tmp != '' && is_dir( $tmp ) && is_writable( $tmp ) ) {
-                               return $tmp;
-                       }
-               }
-
-               // PHP on Windows will detect C:\Windows\Temp as not writable even though PHP can write to
-               // it so create a directory within that called 'mwtmp' with a suffix of the user running
-               // the current process.
-               // The user is included as if various scripts are run by different users they will likely
-               // not be able to access each others temporary files.
-               if ( strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN' ) {
-                       $tmp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'mwtmp-' . get_current_user();
-                       if ( !file_exists( $tmp ) ) {
-                               mkdir( $tmp );
-                       }
-                       if ( is_dir( $tmp ) && is_writable( $tmp ) ) {
-                               return $tmp;
-                       }
-               }
-
-               throw new RuntimeException(
-                       'No writable temporary directory could be found. ' .
-                       'Please explicitly specify a writable directory in configuration.' );
-       }
-
-       /**
-        * Purge this file off the file system
-        *
-        * @return bool Success
-        */
-       public function purge() {
-               $this->canDelete = false; // done
-               MediaWiki\suppressWarnings();
-               $ok = unlink( $this->path );
-               MediaWiki\restoreWarnings();
-
-               unset( self::$pathsCollect[$this->path] );
-
-               return $ok;
-       }
-
-       /**
-        * Clean up the temporary file only after an object goes out of scope
-        *
-        * @param object $object
-        * @return TempFSFile This object
-        */
-       public function bind( $object ) {
-               if ( is_object( $object ) ) {
-                       if ( !isset( $object->tempFSFileReferences ) ) {
-                               // Init first since $object might use __get() and return only a copy variable
-                               $object->tempFSFileReferences = [];
-                       }
-                       $object->tempFSFileReferences[] = $this;
-               }
-
-               return $this;
-       }
-
-       /**
-        * Set flag to not clean up after the temporary file
-        *
-        * @return TempFSFile This object
-        */
-       public function preserve() {
-               $this->canDelete = false;
-
-               unset( self::$pathsCollect[$this->path] );
-
-               return $this;
-       }
-
-       /**
-        * Set flag clean up after the temporary file
-        *
-        * @return TempFSFile This object
-        */
-       public function autocollect() {
-               $this->canDelete = true;
-
-               self::$pathsCollect[$this->path] = 1;
-
-               return $this;
-       }
-
-       /**
-        * Try to make sure that all files are purged on error
-        *
-        * This method should only be called internally
-        */
-       public static function purgeAllOnShutdown() {
-               foreach ( self::$pathsCollect as $path ) {
-                       MediaWiki\suppressWarnings();
-                       unlink( $path );
-                       MediaWiki\restoreWarnings();
-               }
-       }
-
-       /**
-        * Cleans up after the temporary file by deleting it
-        */
-       function __destruct() {
-               if ( $this->canDelete ) {
-                       $this->purge();
-               }
-       }
-}
diff --git a/includes/libs/filebackend/fsfile/FSFile.php b/includes/libs/filebackend/fsfile/FSFile.php
new file mode 100644 (file)
index 0000000..dacad1c
--- /dev/null
@@ -0,0 +1,223 @@
+<?php
+/**
+ * Non-directory file on the file system.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+/**
+ * Class representing a non-directory file on the file system
+ *
+ * @ingroup FileBackend
+ */
+class FSFile {
+       /** @var string Path to file */
+       protected $path;
+
+       /** @var string File SHA-1 in base 36 */
+       protected $sha1Base36;
+
+       /**
+        * Sets up the file object
+        *
+        * @param string $path Path to temporary file on local disk
+        */
+       public function __construct( $path ) {
+               $this->path = $path;
+       }
+
+       /**
+        * Returns the file system path
+        *
+        * @return string
+        */
+       public function getPath() {
+               return $this->path;
+       }
+
+       /**
+        * Checks if the file exists
+        *
+        * @return bool
+        */
+       public function exists() {
+               return is_file( $this->path );
+       }
+
+       /**
+        * Get the file size in bytes
+        *
+        * @return int|bool
+        */
+       public function getSize() {
+               return filesize( $this->path );
+       }
+
+       /**
+        * Get the file's last-modified timestamp
+        *
+        * @return string|bool TS_MW timestamp or false on failure
+        */
+       public function getTimestamp() {
+               MediaWiki\suppressWarnings();
+               $timestamp = filemtime( $this->path );
+               MediaWiki\restoreWarnings();
+               if ( $timestamp !== false ) {
+                       $timestamp = wfTimestamp( TS_MW, $timestamp );
+               }
+
+               return $timestamp;
+       }
+
+       /**
+        * Get an associative array containing information about
+        * a file with the given storage path.
+        *
+        * Resulting array fields include:
+        *   - fileExists
+        *   - size (filesize in bytes)
+        *   - mime (as major/minor)
+        *   - file-mime (as major/minor)
+        *   - sha1 (in base 36)
+        *   - major_mime
+        *   - minor_mime
+        *
+        * @param string|bool $ext The file extension, or true to extract it from the filename.
+        *             Set it to false to ignore the extension. Currently unused.
+        * @return array
+        */
+       public function getProps( $ext = true ) {
+               $info = self::placeholderProps();
+               $info['fileExists'] = $this->exists();
+
+               if ( $info['fileExists'] ) {
+                       $info['size'] = $this->getSize(); // bytes
+                       $info['sha1'] = $this->getSha1Base36();
+
+                       $mime = mime_content_type( $this->path );
+                       # MIME type according to file contents
+                       $info['file-mime'] = ( $mime === false ) ? 'unknown/unknown' : $mime;
+                       # logical MIME type
+                       $info['mime'] = $mime;
+
+                       if ( strpos( $mime, '/' ) !== false ) {
+                               list( $info['major_mime'], $info['minor_mime'] ) = explode( '/', $mime, 2 );
+                       } else {
+                               list( $info['major_mime'], $info['minor_mime'] ) = [ $mime, 'unknown' ];
+                       }
+               }
+
+               return $info;
+       }
+
+       /**
+        * Placeholder file properties to use for files that don't exist
+        *
+        * Resulting array fields include:
+        *   - fileExists
+        *   - size (filesize in bytes)
+        *   - mime (as major/minor)
+        *   - file-mime (as major/minor)
+        *   - sha1 (in base 36)
+        *   - major_mime
+        *   - minor_mime
+        *
+        * @return array
+        */
+       public static function placeholderProps() {
+               $info = [];
+               $info['fileExists'] = false;
+               $info['size'] = 0;
+               $info['file-mime'] = null;
+               $info['major_mime'] = null;
+               $info['minor_mime'] = null;
+               $info['mime'] = null;
+               $info['sha1'] = '';
+
+               return $info;
+       }
+
+       /**
+        * Get a SHA-1 hash of a file in the local filesystem, in base-36 lower case
+        * encoding, zero padded to 31 digits.
+        *
+        * 160 log 2 / log 36 = 30.95, so the 160-bit hash fills 31 digits in base 36
+        * fairly neatly.
+        *
+        * @param bool $recache
+        * @return bool|string False on failure
+        */
+       public function getSha1Base36( $recache = false ) {
+               if ( $this->sha1Base36 !== null && !$recache ) {
+                       return $this->sha1Base36;
+               }
+
+               MediaWiki\suppressWarnings();
+               $this->sha1Base36 = sha1_file( $this->path );
+               MediaWiki\restoreWarnings();
+
+               if ( $this->sha1Base36 !== false ) {
+                       $this->sha1Base36 = Wikimedia\base_convert( $this->sha1Base36, 16, 36, 31 );
+               }
+
+               return $this->sha1Base36;
+       }
+
+       /**
+        * Get the final file extension from a file system path
+        *
+        * @param string $path
+        * @return string
+        */
+       public static function extensionFromPath( $path ) {
+               $i = strrpos( $path, '.' );
+
+               return strtolower( $i ? substr( $path, $i + 1 ) : '' );
+       }
+
+       /**
+        * Get an associative array containing information about a file in the local filesystem.
+        *
+        * @param string $path Absolute local filesystem path
+        * @param string|bool $ext The file extension, or true to extract it from the filename.
+        *   Set it to false to ignore the extension.
+        * @return array
+        */
+       public static function getPropsFromPath( $path, $ext = true ) {
+               $fsFile = new self( $path );
+
+               return $fsFile->getProps( $ext );
+       }
+
+       /**
+        * Get a SHA-1 hash of a file in the local filesystem, in base-36 lower case
+        * encoding, zero padded to 31 digits.
+        *
+        * 160 log 2 / log 36 = 30.95, so the 160-bit hash fills 31 digits in base 36
+        * fairly neatly.
+        *
+        * @param string $path
+        * @return bool|string False on failure
+        */
+       public static function getSha1Base36FromPath( $path ) {
+               $fsFile = new self( $path );
+
+               return $fsFile->getSha1Base36();
+       }
+}
diff --git a/includes/libs/filebackend/fsfile/TempFSFile.php b/includes/libs/filebackend/fsfile/TempFSFile.php
new file mode 100644 (file)
index 0000000..fed6812
--- /dev/null
@@ -0,0 +1,196 @@
+<?php
+/**
+ * Location holder of files stored temporarily
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+/**
+ * This class is used to hold the location and do limited manipulation
+ * of files stored temporarily (this will be whatever wfTempDir() returns)
+ *
+ * @ingroup FileBackend
+ */
+class TempFSFile extends FSFile {
+       /** @var bool Garbage collect the temp file */
+       protected $canDelete = false;
+
+       /** @var array Map of (path => 1) for paths to delete on shutdown */
+       protected static $pathsCollect = null;
+
+       public function __construct( $path ) {
+               parent::__construct( $path );
+
+               if ( self::$pathsCollect === null ) {
+                       self::$pathsCollect = [];
+                       register_shutdown_function( [ __CLASS__, 'purgeAllOnShutdown' ] );
+               }
+       }
+
+       /**
+        * Make a new temporary file on the file system.
+        * Temporary files may be purged when the file object falls out of scope.
+        *
+        * @param string $prefix
+        * @param string $extension Optional file extension
+        * @param string|null $tmpDirectory Optional parent directory
+        * @return TempFSFile|null
+        */
+       public static function factory( $prefix, $extension = '', $tmpDirectory = null ) {
+               $ext = ( $extension != '' ) ? ".{$extension}" : '';
+
+               $attempts = 5;
+               while ( $attempts-- ) {
+                       $hex = sprintf( '%06x%06x', mt_rand( 0, 0xffffff ), mt_rand( 0, 0xffffff ) );
+                       if ( !is_string( $tmpDirectory ) ) {
+                               $tmpDirectory = self::getUsableTempDirectory();
+                       }
+                       $path = wfTempDir() . '/' . $prefix . $hex . $ext;
+                       MediaWiki\suppressWarnings();
+                       $newFileHandle = fopen( $path, 'x' );
+                       MediaWiki\restoreWarnings();
+                       if ( $newFileHandle ) {
+                               fclose( $newFileHandle );
+                               $tmpFile = new self( $path );
+                               $tmpFile->autocollect();
+                               // Safely instantiated, end loop.
+                               return $tmpFile;
+                       }
+               }
+
+               // Give up
+               return null;
+       }
+
+       /**
+        * @return string Filesystem path to a temporary directory
+        * @throws RuntimeException
+        */
+       public static function getUsableTempDirectory() {
+               $tmpDir = array_map( 'getenv', [ 'TMPDIR', 'TMP', 'TEMP' ] );
+               $tmpDir[] = sys_get_temp_dir();
+               $tmpDir[] = ini_get( 'upload_tmp_dir' );
+               foreach ( $tmpDir as $tmp ) {
+                       if ( $tmp != '' && is_dir( $tmp ) && is_writable( $tmp ) ) {
+                               return $tmp;
+                       }
+               }
+
+               // PHP on Windows will detect C:\Windows\Temp as not writable even though PHP can write to
+               // it so create a directory within that called 'mwtmp' with a suffix of the user running
+               // the current process.
+               // The user is included as if various scripts are run by different users they will likely
+               // not be able to access each others temporary files.
+               if ( strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN' ) {
+                       $tmp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'mwtmp-' . get_current_user();
+                       if ( !file_exists( $tmp ) ) {
+                               mkdir( $tmp );
+                       }
+                       if ( is_dir( $tmp ) && is_writable( $tmp ) ) {
+                               return $tmp;
+                       }
+               }
+
+               throw new RuntimeException(
+                       'No writable temporary directory could be found. ' .
+                       'Please explicitly specify a writable directory in configuration.' );
+       }
+
+       /**
+        * Purge this file off the file system
+        *
+        * @return bool Success
+        */
+       public function purge() {
+               $this->canDelete = false; // done
+               MediaWiki\suppressWarnings();
+               $ok = unlink( $this->path );
+               MediaWiki\restoreWarnings();
+
+               unset( self::$pathsCollect[$this->path] );
+
+               return $ok;
+       }
+
+       /**
+        * Clean up the temporary file only after an object goes out of scope
+        *
+        * @param object $object
+        * @return TempFSFile This object
+        */
+       public function bind( $object ) {
+               if ( is_object( $object ) ) {
+                       if ( !isset( $object->tempFSFileReferences ) ) {
+                               // Init first since $object might use __get() and return only a copy variable
+                               $object->tempFSFileReferences = [];
+                       }
+                       $object->tempFSFileReferences[] = $this;
+               }
+
+               return $this;
+       }
+
+       /**
+        * Set flag to not clean up after the temporary file
+        *
+        * @return TempFSFile This object
+        */
+       public function preserve() {
+               $this->canDelete = false;
+
+               unset( self::$pathsCollect[$this->path] );
+
+               return $this;
+       }
+
+       /**
+        * Set flag clean up after the temporary file
+        *
+        * @return TempFSFile This object
+        */
+       public function autocollect() {
+               $this->canDelete = true;
+
+               self::$pathsCollect[$this->path] = 1;
+
+               return $this;
+       }
+
+       /**
+        * Try to make sure that all files are purged on error
+        *
+        * This method should only be called internally
+        */
+       public static function purgeAllOnShutdown() {
+               foreach ( self::$pathsCollect as $path ) {
+                       MediaWiki\suppressWarnings();
+                       unlink( $path );
+                       MediaWiki\restoreWarnings();
+               }
+       }
+
+       /**
+        * Cleans up after the temporary file by deleting it
+        */
+       function __destruct() {
+               if ( $this->canDelete ) {
+                       $this->purge();
+               }
+       }
+}
diff --git a/includes/libs/iterators/IteratorDecorator.php b/includes/libs/iterators/IteratorDecorator.php
new file mode 100644 (file)
index 0000000..c1b5020
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Allows extending classes to decorate an Iterator with
+ * reduced boilerplate.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+abstract class IteratorDecorator implements Iterator {
+       protected $iterator;
+
+       public function __construct( Iterator $iterator ) {
+               $this->iterator = $iterator;
+       }
+
+       public function current() {
+               return $this->iterator->current();
+       }
+
+       public function key() {
+               return $this->iterator->key();
+       }
+
+       public function next() {
+               $this->iterator->next();
+       }
+
+       public function rewind() {
+               $this->iterator->rewind();
+       }
+
+       public function valid() {
+               return $this->iterator->valid();
+       }
+}
diff --git a/includes/libs/iterators/NotRecursiveIterator.php b/includes/libs/iterators/NotRecursiveIterator.php
new file mode 100644 (file)
index 0000000..52ca61b
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Wraps a non-recursive iterator with methods to be recursive
+ * without children.
+ *
+ * Alternatively wraps a recursive iterator to prevent recursing deeper
+ * than the wrapped iterator.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+class NotRecursiveIterator extends IteratorDecorator implements RecursiveIterator {
+       public function hasChildren() {
+               return false;
+       }
+
+       public function getChildren() {
+               return null;
+       }
+}
diff --git a/includes/libs/mime/IEContentAnalyzer.php b/includes/libs/mime/IEContentAnalyzer.php
new file mode 100644 (file)
index 0000000..0d1e527
--- /dev/null
@@ -0,0 +1,851 @@
+<?php
+/**
+ * Simulation of Microsoft Internet Explorer's MIME type detection algorithm.
+ *
+ * @file
+ * @todo Define the exact license of this file.
+ */
+
+/**
+ * This class simulates Microsoft Internet Explorer's terribly broken and
+ * insecure MIME type detection algorithm. It can be used to check web uploads
+ * with an apparently safe type, to see if IE will reinterpret them to produce
+ * something dangerous.
+ *
+ * It is full of bugs and strange design choices should not under any
+ * circumstances be used to determine a MIME type to present to a user or
+ * client. (Apple Safari developers, this means you too.)
+ *
+ * This class is based on a disassembly of IE 5.0, 6.0 and 7.0. Although I have
+ * attempted to ensure that this code works in exactly the same way as Internet
+ * Explorer, it does not share any source code, or creative choices such as
+ * variable names, thus I (Tim Starling) claim copyright on it.
+ *
+ * It may be redistributed without restriction. To aid reuse, this class does
+ * not depend on any MediaWiki module.
+ */
+class IEContentAnalyzer {
+       /**
+        * Relevant data taken from the type table in IE 5
+        */
+       protected $baseTypeTable = [
+               'ambiguous' /*1*/ => [
+                       'text/plain',
+                       'application/octet-stream',
+                       'application/x-netcdf', // [sic]
+               ],
+               'text' /*3*/ => [
+                       'text/richtext', 'image/x-bitmap', 'application/postscript', 'application/base64',
+                       'application/macbinhex40', 'application/x-cdf', 'text/scriptlet'
+               ],
+               'binary' /*4*/ => [
+                       'application/pdf', 'audio/x-aiff', 'audio/basic', 'audio/wav', 'image/gif',
+                       'image/pjpeg', 'image/jpeg', 'image/tiff', 'image/x-png', 'image/png', 'image/bmp',
+                       'image/x-jg', 'image/x-art', 'image/x-emf', 'image/x-wmf', 'video/avi',
+                       'video/x-msvideo', 'video/mpeg', 'application/x-compressed',
+                       'application/x-zip-compressed', 'application/x-gzip-compressed', 'application/java',
+                       'application/x-msdownload'
+               ],
+               'html' /*5*/ => [ 'text/html' ],
+       ];
+
+       /**
+        * Changes to the type table in later versions of IE
+        */
+       protected $addedTypes = [
+               'ie07' => [
+                       'text' => [ 'text/xml', 'application/xml' ]
+               ],
+       ];
+
+       /**
+        * An approximation of the "Content Type" values in HKEY_CLASSES_ROOT in a
+        * typical Windows installation.
+        *
+        * Used for extension to MIME type mapping if detection fails.
+        */
+       protected $registry = [
+               '.323' => 'text/h323',
+               '.3g2' => 'video/3gpp2',
+               '.3gp' => 'video/3gpp',
+               '.3gp2' => 'video/3gpp2',
+               '.3gpp' => 'video/3gpp',
+               '.aac' => 'audio/aac',
+               '.ac3' => 'audio/ac3',
+               '.accda' => 'application/msaccess',
+               '.accdb' => 'application/msaccess',
+               '.accdc' => 'application/msaccess',
+               '.accde' => 'application/msaccess',
+               '.accdr' => 'application/msaccess',
+               '.accdt' => 'application/msaccess',
+               '.ade' => 'application/msaccess',
+               '.adp' => 'application/msaccess',
+               '.adts' => 'audio/aac',
+               '.ai' => 'application/postscript',
+               '.aif' => 'audio/aiff',
+               '.aifc' => 'audio/aiff',
+               '.aiff' => 'audio/aiff',
+               '.amc' => 'application/x-mpeg',
+               '.application' => 'application/x-ms-application',
+               '.asf' => 'video/x-ms-asf',
+               '.asx' => 'video/x-ms-asf',
+               '.au' => 'audio/basic',
+               '.avi' => 'video/avi',
+               '.bmp' => 'image/bmp',
+               '.caf' => 'audio/x-caf',
+               '.cat' => 'application/vnd.ms-pki.seccat',
+               '.cbo' => 'application/sha',
+               '.cdda' => 'audio/aiff',
+               '.cer' => 'application/x-x509-ca-cert',
+               '.conf' => 'text/plain',
+               '.crl' => 'application/pkix-crl',
+               '.crt' => 'application/x-x509-ca-cert',
+               '.css' => 'text/css',
+               '.csv' => 'application/vnd.ms-excel',
+               '.der' => 'application/x-x509-ca-cert',
+               '.dib' => 'image/bmp',
+               '.dif' => 'video/x-dv',
+               '.dll' => 'application/x-msdownload',
+               '.doc' => 'application/msword',
+               '.docm' => 'application/vnd.ms-word.document.macroEnabled.12',
+               '.docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+               '.dot' => 'application/msword',
+               '.dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
+               '.dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+               '.dv' => 'video/x-dv',
+               '.dwfx' => 'model/vnd.dwfx+xps',
+               '.edn' => 'application/vnd.adobe.edn',
+               '.eml' => 'message/rfc822',
+               '.eps' => 'application/postscript',
+               '.etd' => 'application/x-ebx',
+               '.exe' => 'application/x-msdownload',
+               '.fdf' => 'application/vnd.fdf',
+               '.fif' => 'application/fractals',
+               '.gif' => 'image/gif',
+               '.gsm' => 'audio/x-gsm',
+               '.hqx' => 'application/mac-binhex40',
+               '.hta' => 'application/hta',
+               '.htc' => 'text/x-component',
+               '.htm' => 'text/html',
+               '.html' => 'text/html',
+               '.htt' => 'text/webviewhtml',
+               '.hxa' => 'application/xml',
+               '.hxc' => 'application/xml',
+               '.hxd' => 'application/octet-stream',
+               '.hxe' => 'application/xml',
+               '.hxf' => 'application/xml',
+               '.hxh' => 'application/octet-stream',
+               '.hxi' => 'application/octet-stream',
+               '.hxk' => 'application/xml',
+               '.hxq' => 'application/octet-stream',
+               '.hxr' => 'application/octet-stream',
+               '.hxs' => 'application/octet-stream',
+               '.hxt' => 'application/xml',
+               '.hxv' => 'application/xml',
+               '.hxw' => 'application/octet-stream',
+               '.ico' => 'image/x-icon',
+               '.iii' => 'application/x-iphone',
+               '.ins' => 'application/x-internet-signup',
+               '.iqy' => 'text/x-ms-iqy',
+               '.isp' => 'application/x-internet-signup',
+               '.jfif' => 'image/jpeg',
+               '.jnlp' => 'application/x-java-jnlp-file',
+               '.jpe' => 'image/jpeg',
+               '.jpeg' => 'image/jpeg',
+               '.jpg' => 'image/jpeg',
+               '.jtx' => 'application/x-jtx+xps',
+               '.latex' => 'application/x-latex',
+               '.log' => 'text/plain',
+               '.m1v' => 'video/mpeg',
+               '.m2v' => 'video/mpeg',
+               '.m3u' => 'audio/x-mpegurl',
+               '.mac' => 'image/x-macpaint',
+               '.man' => 'application/x-troff-man',
+               '.mda' => 'application/msaccess',
+               '.mdb' => 'application/msaccess',
+               '.mde' => 'application/msaccess',
+               '.mfp' => 'application/x-shockwave-flash',
+               '.mht' => 'message/rfc822',
+               '.mhtml' => 'message/rfc822',
+               '.mid' => 'audio/mid',
+               '.midi' => 'audio/mid',
+               '.mod' => 'video/mpeg',
+               '.mov' => 'video/quicktime',
+               '.mp2' => 'video/mpeg',
+               '.mp2v' => 'video/mpeg',
+               '.mp3' => 'audio/mpeg',
+               '.mp4' => 'video/mp4',
+               '.mpa' => 'video/mpeg',
+               '.mpe' => 'video/mpeg',
+               '.mpeg' => 'video/mpeg',
+               '.mpf' => 'application/vnd.ms-mediapackage',
+               '.mpg' => 'video/mpeg',
+               '.mpv2' => 'video/mpeg',
+               '.mqv' => 'video/quicktime',
+               '.NMW' => 'application/nmwb',
+               '.nws' => 'message/rfc822',
+               '.odc' => 'text/x-ms-odc',
+               '.ols' => 'application/vnd.ms-publisher',
+               '.p10' => 'application/pkcs10',
+               '.p12' => 'application/x-pkcs12',
+               '.p7b' => 'application/x-pkcs7-certificates',
+               '.p7c' => 'application/pkcs7-mime',
+               '.p7m' => 'application/pkcs7-mime',
+               '.p7r' => 'application/x-pkcs7-certreqresp',
+               '.p7s' => 'application/pkcs7-signature',
+               '.pct' => 'image/pict',
+               '.pdf' => 'application/pdf',
+               '.pdx' => 'application/vnd.adobe.pdx',
+               '.pfx' => 'application/x-pkcs12',
+               '.pic' => 'image/pict',
+               '.pict' => 'image/pict',
+               '.pinstall' => 'application/x-picasa-detect',
+               '.pko' => 'application/vnd.ms-pki.pko',
+               '.png' => 'image/png',
+               '.pnt' => 'image/x-macpaint',
+               '.pntg' => 'image/x-macpaint',
+               '.pot' => 'application/vnd.ms-powerpoint',
+               '.potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
+               '.potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+               '.ppa' => 'application/vnd.ms-powerpoint',
+               '.ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
+               '.pps' => 'application/vnd.ms-powerpoint',
+               '.ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
+               '.ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+               '.ppt' => 'application/vnd.ms-powerpoint',
+               '.pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
+               '.pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+               '.prf' => 'application/pics-rules',
+               '.ps' => 'application/postscript',
+               '.pub' => 'application/vnd.ms-publisher',
+               '.pwz' => 'application/vnd.ms-powerpoint',
+               '.py' => 'text/plain',
+               '.pyw' => 'text/plain',
+               '.qht' => 'text/x-html-insertion',
+               '.qhtm' => 'text/x-html-insertion',
+               '.qt' => 'video/quicktime',
+               '.qti' => 'image/x-quicktime',
+               '.qtif' => 'image/x-quicktime',
+               '.qtl' => 'application/x-quicktimeplayer',
+               '.rat' => 'application/rat-file',
+               '.rmf' => 'application/vnd.adobe.rmf',
+               '.rmi' => 'audio/mid',
+               '.rqy' => 'text/x-ms-rqy',
+               '.rtf' => 'application/msword',
+               '.sct' => 'text/scriptlet',
+               '.sd2' => 'audio/x-sd2',
+               '.sdp' => 'application/sdp',
+               '.shtml' => 'text/html',
+               '.sit' => 'application/x-stuffit',
+               '.sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
+               '.sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+               '.slk' => 'application/vnd.ms-excel',
+               '.snd' => 'audio/basic',
+               '.so' => 'application/x-apachemodule',
+               '.sol' => 'text/plain',
+               '.sor' => 'text/plain',
+               '.spc' => 'application/x-pkcs7-certificates',
+               '.spl' => 'application/futuresplash',
+               '.sst' => 'application/vnd.ms-pki.certstore',
+               '.stl' => 'application/vnd.ms-pki.stl',
+               '.swf' => 'application/x-shockwave-flash',
+               '.thmx' => 'application/vnd.ms-officetheme',
+               '.tif' => 'image/tiff',
+               '.tiff' => 'image/tiff',
+               '.txt' => 'text/plain',
+               '.uls' => 'text/iuls',
+               '.vcf' => 'text/x-vcard',
+               '.vdx' => 'application/vnd.ms-visio.viewer',
+               '.vsd' => 'application/vnd.ms-visio.viewer',
+               '.vss' => 'application/vnd.ms-visio.viewer',
+               '.vst' => 'application/vnd.ms-visio.viewer',
+               '.vsx' => 'application/vnd.ms-visio.viewer',
+               '.vtx' => 'application/vnd.ms-visio.viewer',
+               '.wav' => 'audio/wav',
+               '.wax' => 'audio/x-ms-wax',
+               '.wbk' => 'application/msword',
+               '.wdp' => 'image/vnd.ms-photo',
+               '.wiz' => 'application/msword',
+               '.wm' => 'video/x-ms-wm',
+               '.wma' => 'audio/x-ms-wma',
+               '.wmd' => 'application/x-ms-wmd',
+               '.wmv' => 'video/x-ms-wmv',
+               '.wmx' => 'video/x-ms-wmx',
+               '.wmz' => 'application/x-ms-wmz',
+               '.wpl' => 'application/vnd.ms-wpl',
+               '.wsc' => 'text/scriptlet',
+               '.wvx' => 'video/x-ms-wvx',
+               '.xaml' => 'application/xaml+xml',
+               '.xbap' => 'application/x-ms-xbap',
+               '.xdp' => 'application/vnd.adobe.xdp+xml',
+               '.xfdf' => 'application/vnd.adobe.xfdf',
+               '.xht' => 'application/xhtml+xml',
+               '.xhtml' => 'application/xhtml+xml',
+               '.xla' => 'application/vnd.ms-excel',
+               '.xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
+               '.xlk' => 'application/vnd.ms-excel',
+               '.xll' => 'application/vnd.ms-excel',
+               '.xlm' => 'application/vnd.ms-excel',
+               '.xls' => 'application/vnd.ms-excel',
+               '.xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+               '.xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
+               '.xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+               '.xlt' => 'application/vnd.ms-excel',
+               '.xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
+               '.xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+               '.xlw' => 'application/vnd.ms-excel',
+               '.xml' => 'text/xml',
+               '.xps' => 'application/vnd.ms-xpsdocument',
+               '.xsl' => 'text/xml',
+       ];
+
+       /**
+        * IE versions which have been analysed to bring you this class, and for
+        * which some substantive difference exists. These will appear as keys
+        * in the return value of getRealMimesFromData(). The names are chosen to sort correctly.
+        */
+       protected $versions = [ 'ie05', 'ie06', 'ie07', 'ie07.strict', 'ie07.nohtml' ];
+
+       /**
+        * Type table with versions expanded
+        */
+       protected $typeTable = [];
+
+       /** constructor */
+       function __construct() {
+               // Construct versioned type arrays from the base type array plus additions
+               $types = $this->baseTypeTable;
+               foreach ( $this->versions as $version ) {
+                       if ( isset( $this->addedTypes[$version] ) ) {
+                               foreach ( $this->addedTypes[$version] as $format => $addedTypes ) {
+                                       $types[$format] = array_merge( $types[$format], $addedTypes );
+                               }
+                       }
+                       $this->typeTable[$version] = $types;
+               }
+       }
+
+       /**
+        * Get the MIME types from getMimesFromData(), but convert the result from IE's
+        * idiosyncratic private types into something other apps will understand.
+        *
+        * @param string $fileName the file name (unused at present)
+        * @param string $chunk the first 256 bytes of the file
+        * @param string $proposed the MIME type proposed by the server
+        *
+        * @return Array: map of IE version to detected MIME type
+        */
+       public function getRealMimesFromData( $fileName, $chunk, $proposed ) {
+               $types = $this->getMimesFromData( $fileName, $chunk, $proposed );
+               $types = array_map( [ $this, 'translateMimeType' ], $types );
+               return $types;
+       }
+
+       /**
+        * Translate a MIME type from IE's idiosyncratic private types into
+        * more commonly understood type strings
+        * @param $type
+        * @return string
+        */
+       public function translateMimeType( $type ) {
+               static $table = [
+                       'image/pjpeg' => 'image/jpeg',
+                       'image/x-png' => 'image/png',
+                       'image/x-wmf' => 'application/x-msmetafile',
+                       'image/bmp' => 'image/x-bmp',
+                       'application/x-zip-compressed' => 'application/zip',
+                       'application/x-compressed' => 'application/x-compress',
+                       'application/x-gzip-compressed' => 'application/x-gzip',
+                       'audio/mid' => 'audio/midi',
+               ];
+               if ( isset( $table[$type] ) ) {
+                       $type = $table[$type];
+               }
+               return $type;
+       }
+
+       /**
+        * Get the untranslated MIME types for all known versions
+        *
+        * @param string $fileName the file name (unused at present)
+        * @param string $chunk the first 256 bytes of the file
+        * @param string $proposed the MIME type proposed by the server
+        *
+        * @return Array: map of IE version to detected MIME type
+        */
+       public function getMimesFromData( $fileName, $chunk, $proposed ) {
+               $types = [];
+               foreach ( $this->versions as $version ) {
+                       $types[$version] = $this->getMimeTypeForVersion( $version, $fileName, $chunk, $proposed );
+               }
+               return $types;
+       }
+
+       /**
+        * Get the MIME type for a given named version
+        * @param $version
+        * @param $fileName
+        * @param $chunk
+        * @param $proposed
+        * @return bool|string
+        */
+       protected function getMimeTypeForVersion( $version, $fileName, $chunk, $proposed ) {
+               // Strip text after a semicolon
+               $semiPos = strpos( $proposed, ';' );
+               if ( $semiPos !== false ) {
+                       $proposed = substr( $proposed, 0, $semiPos );
+               }
+
+               $proposedFormat = $this->getDataFormat( $version, $proposed );
+               if ( $proposedFormat == 'unknown'
+                       && $proposed != 'multipart/mixed'
+                       && $proposed != 'multipart/x-mixed-replace' )
+               {
+                       return $proposed;
+               }
+               if ( strval( $chunk ) === '' ) {
+                       return $proposed;
+               }
+
+               // Truncate chunk at 255 bytes
+               $chunk = substr( $chunk, 0, 255 );
+
+               // IE does the Check*Headers() calls last, and instead does the following image
+               // type checks by directly looking for the magic numbers. What I do here should
+               // have the same effect since the magic number checks are identical in both cases.
+               $result = $this->sampleData( $version, $chunk );
+               $sampleFound = $result['found'];
+               $counters = $result['counters'];
+               $binaryType = $this->checkBinaryHeaders( $version, $chunk );
+               $textType = $this->checkTextHeaders( $version, $chunk );
+
+               if ( $proposed == 'text/html' && isset( $sampleFound['html'] ) ) {
+                       return 'text/html';
+               }
+               if ( $proposed == 'image/gif' && $binaryType == 'image/gif' ) {
+                       return 'image/gif';
+               }
+               if ( ( $proposed == 'image/pjpeg' || $proposed == 'image/jpeg' )
+                       && $binaryType == 'image/pjpeg' )
+               {
+                       return $proposed;
+               }
+               // PNG check added in IE 7
+               if ( $version >= 'ie07'
+                       && ( $proposed == 'image/x-png' || $proposed == 'image/png' )
+                       && $binaryType == 'image/x-png' )
+               {
+                       return $proposed;
+               }
+
+               // CDF was removed in IE 7 so it won't be in $sampleFound for later versions
+               if ( isset( $sampleFound['cdf'] ) ) {
+                       return 'application/x-cdf';
+               }
+
+               // RSS and Atom were added in IE 7 so they won't be in $sampleFound for
+               // previous versions
+               if ( isset( $sampleFound['rss'] ) ) {
+                       return 'application/rss+xml';
+               }
+               if ( isset( $sampleFound['rdf-tag'] )
+                       && isset( $sampleFound['rdf-url'] )
+                       && isset( $sampleFound['rdf-purl'] ) )
+               {
+                       return 'application/rss+xml';
+               }
+               if ( isset( $sampleFound['atom'] ) ) {
+                       return 'application/atom+xml';
+               }
+
+               if ( isset( $sampleFound['xml'] ) ) {
+                       // TODO: I'm not sure under what circumstances this flag is enabled
+                       if ( strpos( $version, 'strict' ) !== false ) {
+                               if ( $proposed == 'text/html' || $proposed == 'text/xml' ) {
+                                       return 'text/xml';
+                               }
+                       } else {
+                               return 'text/xml';
+                       }
+               }
+               if ( isset( $sampleFound['html'] ) ) {
+                       // TODO: I'm not sure under what circumstances this flag is enabled
+                       if ( strpos( $version, 'nohtml' ) !== false ) {
+                               if ( $proposed == 'text/plain' ) {
+                                       return 'text/html';
+                               }
+                       } else {
+                               return 'text/html';
+                       }
+               }
+               if ( isset( $sampleFound['xbm'] ) ) {
+                       return 'image/x-bitmap';
+               }
+               if ( isset( $sampleFound['binhex'] ) ) {
+                       return 'application/macbinhex40';
+               }
+               if ( isset( $sampleFound['scriptlet'] ) ) {
+                       if ( strpos( $version, 'strict' ) !== false ) {
+                               if ( $proposed == 'text/plain' || $proposed == 'text/scriptlet' ) {
+                                       return 'text/scriptlet';
+                               }
+                       } else {
+                               return 'text/scriptlet';
+                       }
+               }
+
+               // Freaky heuristics to determine if the data is text or binary
+               // The heuristic is of course broken for non-ASCII text
+               if ( $counters['ctrl'] != 0 && ( $counters['ff'] + $counters['low'] )
+                       < ( $counters['ctrl'] + $counters['high'] ) * 16 )
+               {
+                       $kindOfBinary = true;
+                       $type = $binaryType ? $binaryType : $textType;
+                       if ( $type === false ) {
+                               $type = 'application/octet-stream';
+                       }
+               } else {
+                       $kindOfBinary = false;
+                       $type = $textType ? $textType : $binaryType;
+                       if ( $type === false ) {
+                               $type = 'text/plain';
+                       }
+               }
+
+               // Check if the output format is ambiguous
+               // This generally means that detection failed, real types aren't ambiguous
+               $detectedFormat = $this->getDataFormat( $version, $type );
+               if ( $detectedFormat != 'ambiguous' ) {
+                       return $type;
+               }
+
+               if ( $proposedFormat != 'ambiguous' ) {
+                       // FormatAgreesWithData()
+                       if ( $proposedFormat == 'text' && !$kindOfBinary ) {
+                               return $proposed;
+                       }
+                       if ( $proposedFormat == 'binary' && $kindOfBinary ) {
+                               return $proposed;
+                       }
+                       if ( $proposedFormat == 'html' ) {
+                               return $proposed;
+                       }
+               }
+
+               // Find a MIME type by searching the registry for the file extension.
+               $dotPos = strrpos( $fileName, '.' );
+               if ( $dotPos === false ) {
+                       return $type;
+               }
+               $ext = substr( $fileName, $dotPos );
+               if ( isset( $this->registry[$ext] ) ) {
+                       return $this->registry[$ext];
+               }
+
+               // TODO: If the extension has an application registered to it, IE will return
+               // application/octet-stream. We'll skip that, so we could erroneously
+               // return text/plain or application/x-netcdf where application/octet-stream
+               // would be correct.
+
+               return $type;
+       }
+
+       /**
+        * Check for text headers at the start of the chunk
+        * Confirmed same in 5 and 7.
+        * @param $version
+        * @param $chunk
+        * @return bool|string
+        */
+       private function checkTextHeaders( $version, $chunk ) {
+               $chunk2 = substr( $chunk, 0, 2 );
+               $chunk4 = substr( $chunk, 0, 4 );
+               $chunk5 = substr( $chunk, 0, 5 );
+               if ( $chunk4 == '%PDF' ) {
+                       return 'application/pdf';
+               }
+               if ( $chunk2 == '%!' ) {
+                       return 'application/postscript';
+               }
+               if ( $chunk5 == '{\\rtf' ) {
+                       return 'text/richtext';
+               }
+               if ( $chunk5 == 'begin' ) {
+                       return 'application/base64';
+               }
+               return false;
+       }
+
+       /**
+        * Check for binary headers at the start of the chunk
+        * Confirmed same in 5 and 7.
+        * @param $version
+        * @param $chunk
+        * @return bool|string
+        */
+       private function checkBinaryHeaders( $version, $chunk ) {
+               $chunk2 = substr( $chunk, 0, 2 );
+               $chunk3 = substr( $chunk, 0, 3 );
+               $chunk4 = substr( $chunk, 0, 4 );
+               $chunk5 = substr( $chunk, 0, 5 );
+               $chunk5uc = strtoupper( $chunk5 );
+               $chunk8 = substr( $chunk, 0, 8 );
+               if ( $chunk5uc == 'GIF87' || $chunk5uc == 'GIF89' ) {
+                       return 'image/gif';
+               }
+               if ( $chunk2 == "\xff\xd8" ) {
+                       return 'image/pjpeg'; // actually plain JPEG but this is what IE returns
+               }
+
+               if ( $chunk2 == 'BM'
+                       && substr( $chunk, 6, 2 ) == "\000\000"
+                       && substr( $chunk, 8, 2 ) == "\000\000" )
+               {
+                       return 'image/bmp'; // another non-standard MIME
+               }
+               if ( $chunk4 == 'RIFF'
+                       && substr( $chunk, 8, 4 ) == 'WAVE' )
+               {
+                       return 'audio/wav';
+               }
+               // These were integer literals in IE
+               // Perhaps the author was not sure what the target endianness was
+               if ( $chunk4 == ".sd\000"
+                       || $chunk4 == ".snd"
+                       || $chunk4 == "\000ds."
+                       || $chunk4 == "dns." )
+               {
+                       return 'audio/basic';
+               }
+               if ( $chunk3 == "MM\000" ) {
+                       return 'image/tiff';
+               }
+               if ( $chunk2 == 'MZ' ) {
+                       return 'application/x-msdownload';
+               }
+               if ( $chunk8 == "\x89PNG\x0d\x0a\x1a\x0a" ) {
+                       return 'image/x-png'; // [sic]
+               }
+               if ( strlen( $chunk ) >= 5 ) {
+                       $byte2 = ord( $chunk[2] );
+                       $byte4 = ord( $chunk[4] );
+                       if ( $byte2 >= 3 && $byte2 <= 31 && $byte4 == 0 && $chunk2 == 'JG' ) {
+                               return 'image/x-jg';
+                       }
+               }
+               // More endian confusion?
+               if ( $chunk4 == 'MROF' ) {
+                       return 'audio/x-aiff';
+               }
+               $chunk4_8 = substr( $chunk, 8, 4 );
+               if ( $chunk4 == 'FORM' && ( $chunk4_8 == 'AIFF' || $chunk4_8 == 'AIFC' ) ) {
+                       return 'audio/x-aiff';
+               }
+               if ( $chunk4 == 'RIFF' && $chunk4_8 == 'AVI ' ) {
+                       return 'video/avi';
+               }
+               if ( $chunk4 == "\x00\x00\x01\xb3" || $chunk4 == "\x00\x00\x01\xba" ) {
+                       return 'video/mpeg';
+               }
+               if ( $chunk4 == "\001\000\000\000"
+                       && substr( $chunk, 40, 4 ) == ' EMF' )
+               {
+                       return 'image/x-emf';
+               }
+               if ( $chunk4 == "\xd7\xcd\xc6\x9a" ) {
+                       return 'image/x-wmf';
+               }
+               if ( $chunk4 == "\xca\xfe\xba\xbe" ) {
+                       return 'application/java';
+               }
+               if ( $chunk2 == 'PK' ) {
+                       return 'application/x-zip-compressed';
+               }
+               if ( $chunk2 == "\x1f\x9d" ) {
+                       return 'application/x-compressed';
+               }
+               if ( $chunk2 == "\x1f\x8b" ) {
+                       return 'application/x-gzip-compressed';
+               }
+               // Skip redundant check for ZIP
+               if ( $chunk5 == "MThd\000" ) {
+                       return 'audio/mid';
+               }
+               if ( $chunk4 == '%PDF' ) {
+                       return 'application/pdf';
+               }
+               return false;
+       }
+
+       /**
+        * Do heuristic checks on the bulk of the data sample.
+        * Search for HTML tags.
+        * @param $version
+        * @param $chunk
+        * @return array
+        */
+       protected function sampleData( $version, $chunk ) {
+               $found = [];
+               $counters = [
+                       'ctrl' => 0,
+                       'high' => 0,
+                       'low' => 0,
+                       'lf' => 0,
+                       'cr' => 0,
+                       'ff' => 0
+               ];
+               $htmlTags = [
+                       'html',
+                       'head',
+                       'title',
+                       'body',
+                       'script',
+                       'a href',
+                       'pre',
+                       'img',
+                       'plaintext',
+                       'table'
+               ];
+               $rdfUrl = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+               $rdfPurl = 'http://purl.org/rss/1.0/';
+               $xbmMagic1 = '#define';
+               $xbmMagic2 = '_width';
+               $xbmMagic3 = '_bits';
+               $binhexMagic = 'converted with BinHex';
+               $chunkLength = strlen( $chunk );
+
+               for ( $offset = 0; $offset < $chunkLength; $offset++ ) {
+                       $curChar = $chunk[$offset];
+                       if ( $curChar == "\x0a" ) {
+                               $counters['lf']++;
+                               continue;
+                       } elseif ( $curChar == "\x0d" ) {
+                               $counters['cr']++;
+                               continue;
+                       } elseif ( $curChar == "\x0c" ) {
+                               $counters['ff']++;
+                               continue;
+                       } elseif ( $curChar == "\t" ) {
+                               $counters['low']++;
+                               continue;
+                       } elseif ( ord( $curChar ) < 32 ) {
+                               $counters['ctrl']++;
+                               continue;
+                       } elseif ( ord( $curChar ) >= 128 ) {
+                               $counters['high']++;
+                               continue;
+                       }
+
+                       $counters['low']++;
+                       if ( $curChar == '<' ) {
+                               // XML
+                               $remainder = substr( $chunk, $offset + 1 );
+                               if ( !strncasecmp( $remainder, '?XML', 4 ) ) {
+                                       $nextChar = substr( $chunk, $offset + 5, 1 );
+                                       if ( $nextChar == ':' || $nextChar == ' ' || $nextChar == "\t" ) {
+                                               $found['xml'] = true;
+                                       }
+                               }
+                               // Scriptlet (JSP)
+                               if ( !strncasecmp( $remainder, 'SCRIPTLET', 9 ) ) {
+                                       $found['scriptlet'] = true;
+                                       break;
+                               }
+                               // HTML
+                               foreach ( $htmlTags as $tag ) {
+                                       if ( !strncasecmp( $remainder, $tag, strlen( $tag ) ) ) {
+                                               $found['html'] = true;
+                                       }
+                               }
+                               // Skip broken check for additional tags (HR etc.)
+
+                               // CHANNEL replaced by RSS, RDF and FEED in IE 7
+                               if ( $version < 'ie07' ) {
+                                       if ( !strncasecmp( $remainder, 'CHANNEL', 7 ) ) {
+                                               $found['cdf'] = true;
+                                       }
+                               } else {
+                                       // RSS
+                                       if ( !strncasecmp( $remainder, 'RSS', 3 ) ) {
+                                               $found['rss'] = true;
+                                               break; // return from SampleData
+                                       }
+                                       if ( !strncasecmp( $remainder, 'rdf:RDF', 7 ) ) {
+                                               $found['rdf-tag'] = true;
+                                               // no break
+                                       }
+                                       if ( !strncasecmp( $remainder, 'FEED', 4 ) ) {
+                                               $found['atom'] = true;
+                                               break;
+                                       }
+                               }
+                               continue;
+                       }
+                       // Skip broken check for -->
+
+                       // RSS URL checks
+                       // For some reason both URLs must appear before it is recognised
+                       $remainder = substr( $chunk, $offset );
+                       if ( !strncasecmp( $remainder, $rdfUrl, strlen( $rdfUrl ) ) ) {
+                               $found['rdf-url'] = true;
+                               if ( isset( $found['rdf-tag'] )
+                                       && isset( $found['rdf-purl'] ) ) // [sic]
+                               {
+                                       break;
+                               }
+                               continue;
+                       }
+
+                       if ( !strncasecmp( $remainder, $rdfPurl, strlen( $rdfPurl ) ) ) {
+                               if ( isset( $found['rdf-tag'] )
+                                       && isset( $found['rdf-url'] ) ) // [sic]
+                               {
+                                       break;
+                               }
+                               continue;
+                       }
+
+                       // XBM checks
+                       if ( !strncasecmp( $remainder, $xbmMagic1, strlen( $xbmMagic1 ) ) ) {
+                               $found['xbm1'] = true;
+                               continue;
+                       }
+                       if ( $curChar == '_' ) {
+                               if ( isset( $found['xbm2'] ) ) {
+                                       if ( !strncasecmp( $remainder, $xbmMagic3, strlen( $xbmMagic3 ) ) ) {
+                                               $found['xbm'] = true;
+                                               break;
+                                       }
+                               } elseif ( isset( $found['xbm1'] ) ) {
+                                       if ( !strncasecmp( $remainder, $xbmMagic2, strlen( $xbmMagic2 ) ) ) {
+                                               $found['xbm2'] = true;
+                                       }
+                               }
+                       }
+
+                       // BinHex
+                       if ( !strncmp( $remainder, $binhexMagic, strlen( $binhexMagic ) ) ) {
+                               $found['binhex'] = true;
+                       }
+               }
+               return [ 'found' => $found, 'counters' => $counters ];
+       }
+
+       /**
+        * @param $version
+        * @param $type
+        * @return int|string
+        */
+       protected function getDataFormat( $version, $type ) {
+               $types = $this->typeTable[$version];
+               if ( $type == '(null)' || strval( $type ) === '' ) {
+                       return 'ambiguous';
+               }
+               foreach ( $types as $format => $list ) {
+                       if ( in_array( $type, $list ) ) {
+                               return $format;
+                       }
+               }
+               return 'unknown';
+       }
+}
diff --git a/includes/libs/mime/MimeAnalyzer.php b/includes/libs/mime/MimeAnalyzer.php
new file mode 100644 (file)
index 0000000..5f4d7c9
--- /dev/null
@@ -0,0 +1,1166 @@
+<?php
+/**
+ * Module defining helper functions for detecting and dealing with MIME types.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Implements functions related to MIME types such as detection and mapping to file extension
+ *
+ * @since 1.28
+ */
+class MimeAnalyzer implements LoggerAwareInterface {
+       /** @var string */
+       protected $typeFile;
+       /** @var string */
+       protected $infoFile;
+       /** @var string */
+       protected $xmlTypes;
+       /** @var callable */
+       protected $initCallback;
+       /** @var callable */
+       protected $detectCallback;
+       /** @var callable */
+       protected $guessCallback;
+       /** @var callable */
+       protected $extCallback;
+       /** @var array Mapping of media types to arrays of MIME types */
+       protected $mediaTypes = null;
+       /** @var array Map of MIME type aliases */
+       protected $mimeTypeAliases = null;
+       /** @var array Map of MIME types to file extensions (as a space separated list) */
+       protected $mimetoExt = null;
+
+       /** @var array Map of file extensions types to MIME types (as a space separated list) */
+       public $mExtToMime = null; // legacy name; field accessed by hooks
+
+       /** @var IEContentAnalyzer */
+       protected $IEAnalyzer;
+
+       /** @var string Extra MIME types, set for example by media handling extensions */
+       private $extraTypes = '';
+       /** @var string Extra MIME info, set for example by media handling extensions */
+       private $extraInfo = '';
+
+       /** @var LoggerInterface */
+       private $logger;
+
+       /**
+        * Defines a set of well known MIME types
+        * This is used as a fallback to mime.types files.
+        * An extensive list of well known MIME types is provided by
+        * the file mime.types in the includes directory.
+        *
+        * This list concatenated with mime.types is used to create a MIME <-> ext
+        * map. Each line contains a MIME type followed by a space separated list of
+        * extensions. If multiple extensions for a single MIME type exist or if
+        * multiple MIME types exist for a single extension then in most cases
+        * MediaWiki assumes that the first extension following the MIME type is the
+        * canonical extension, and the first time a MIME type appears for a certain
+        * extension is considered the canonical MIME type.
+        *
+        * (Note that appending the type file list to the end of self::$wellKnownTypes
+        * sucks because you can't redefine canonical types. This could be fixed by
+        * appending self::$wellKnownTypes behind type file list, but who knows
+        * what will break? In practice this probably isn't a problem anyway -- Bryan)
+        */
+       protected static $wellKnownTypes = <<<EOT
+application/ogg ogx ogg ogm ogv oga spx
+application/pdf pdf
+application/vnd.oasis.opendocument.chart odc
+application/vnd.oasis.opendocument.chart-template otc
+application/vnd.oasis.opendocument.database odb
+application/vnd.oasis.opendocument.formula odf
+application/vnd.oasis.opendocument.formula-template otf
+application/vnd.oasis.opendocument.graphics odg
+application/vnd.oasis.opendocument.graphics-template otg
+application/vnd.oasis.opendocument.image odi
+application/vnd.oasis.opendocument.image-template oti
+application/vnd.oasis.opendocument.presentation odp
+application/vnd.oasis.opendocument.presentation-template otp
+application/vnd.oasis.opendocument.spreadsheet ods
+application/vnd.oasis.opendocument.spreadsheet-template ots
+application/vnd.oasis.opendocument.text odt
+application/vnd.oasis.opendocument.text-master otm
+application/vnd.oasis.opendocument.text-template ott
+application/vnd.oasis.opendocument.text-web oth
+application/javascript js
+application/x-shockwave-flash swf
+audio/midi mid midi kar
+audio/mpeg mpga mpa mp2 mp3
+audio/x-aiff aif aiff aifc
+audio/x-wav wav
+audio/ogg oga spx ogg
+image/x-bmp bmp
+image/gif gif
+image/jpeg jpeg jpg jpe
+image/png png
+image/svg+xml svg
+image/svg svg
+image/tiff tiff tif
+image/vnd.djvu djvu
+image/x.djvu djvu
+image/x-djvu djvu
+image/x-portable-pixmap ppm
+image/x-xcf xcf
+text/plain txt
+text/html html htm
+video/ogg ogv ogm ogg
+video/mpeg mpg mpeg
+EOT;
+
+       /**
+        * Defines a set of well known MIME info entries
+        * This is used as a fallback to mime.info files.
+        * An extensive list of well known MIME types is provided by
+        * the file mime.info in the includes directory.
+        */
+       protected static $wellKnownInfo = <<<EOT
+application/pdf [OFFICE]
+application/vnd.oasis.opendocument.chart [OFFICE]
+application/vnd.oasis.opendocument.chart-template [OFFICE]
+application/vnd.oasis.opendocument.database [OFFICE]
+application/vnd.oasis.opendocument.formula [OFFICE]
+application/vnd.oasis.opendocument.formula-template [OFFICE]
+application/vnd.oasis.opendocument.graphics [OFFICE]
+application/vnd.oasis.opendocument.graphics-template [OFFICE]
+application/vnd.oasis.opendocument.image [OFFICE]
+application/vnd.oasis.opendocument.image-template [OFFICE]
+application/vnd.oasis.opendocument.presentation [OFFICE]
+application/vnd.oasis.opendocument.presentation-template [OFFICE]
+application/vnd.oasis.opendocument.spreadsheet [OFFICE]
+application/vnd.oasis.opendocument.spreadsheet-template [OFFICE]
+application/vnd.oasis.opendocument.text [OFFICE]
+application/vnd.oasis.opendocument.text-template [OFFICE]
+application/vnd.oasis.opendocument.text-master [OFFICE]
+application/vnd.oasis.opendocument.text-web [OFFICE]
+application/javascript text/javascript application/x-javascript [EXECUTABLE]
+application/x-shockwave-flash [MULTIMEDIA]
+audio/midi [AUDIO]
+audio/x-aiff [AUDIO]
+audio/x-wav [AUDIO]
+audio/mp3 audio/mpeg [AUDIO]
+application/ogg audio/ogg video/ogg [MULTIMEDIA]
+image/x-bmp image/x-ms-bmp image/bmp [BITMAP]
+image/gif [BITMAP]
+image/jpeg [BITMAP]
+image/png [BITMAP]
+image/svg+xml [DRAWING]
+image/tiff [BITMAP]
+image/vnd.djvu [BITMAP]
+image/x-xcf [BITMAP]
+image/x-portable-pixmap [BITMAP]
+text/plain [TEXT]
+text/html [TEXT]
+video/ogg [VIDEO]
+video/mpeg [VIDEO]
+unknown/unknown application/octet-stream application/x-empty [UNKNOWN]
+EOT;
+
+       /**
+        * @param array $params Configuration map, includes:
+        *   - typeFile: path to file with the list of known MIME types
+        *   - infoFile: path to file with the MIME type info
+        *   - xmlTypes: map of root element names to XML MIME types
+        *   - initCallback: initialization callback that is passed this object [optional]
+        *   - detectCallback: alternative to finfo that returns the mime type for a file.
+        *      For example, the callback can return the output of "file -bi". [optional]
+        *   - guessCallback: callback to improve the guessed MIME type using the file data.
+        *      This is intended for fixing mistakes in fileinfo or "detectCallback". [optional]
+        *   - extCallback: callback to improve the guessed MIME type using the extension. [optional]
+        *   - logger: PSR-3 logger [optional]
+        * @note Constructing these instances is expensive due to file reads.
+        *  A service or singleton pattern should be used to avoid creating instances again and again.
+        */
+       public function __construct( array $params ) {
+               $this->typeFile = $params['typeFile'];
+               $this->infoFile = $params['infoFile'];
+               $this->xmlTypes = $params['xmlTypes'];
+               $this->initCallback = isset( $params['initCallback'] )
+                       ? $params['initCallback']
+                       : null;
+               $this->detectCallback = isset( $params['detectCallback'] )
+                       ? $params['detectCallback']
+                       : null;
+               $this->guessCallback = isset( $params['guessCallback'] )
+                       ? $params['guessCallback']
+                       : null;
+               $this->extCallback = isset( $params['extCallback'] )
+                       ? $params['extCallback']
+                       : null;
+               $this->logger = isset( $params['logger'] )
+                       ? $params['logger']
+                       : new \Psr\Log\NullLogger();
+
+               $this->loadFiles();
+       }
+
+       protected function loadFiles() {
+               /**
+                *   --- load mime.types ---
+                */
+
+               # Allow media handling extensions adding MIME-types and MIME-info
+               if ( $this->initCallback ) {
+                       call_user_func( $this->initCallback, $this );
+               }
+
+               $types = self::$wellKnownTypes;
+
+               $mimeTypeFile = $this->typeFile;
+               if ( $mimeTypeFile ) {
+                       if ( is_file( $mimeTypeFile ) && is_readable( $mimeTypeFile ) ) {
+                               $this->logger->info( __METHOD__ . ": loading mime types from $mimeTypeFile\n" );
+                               $types .= "\n";
+                               $types .= file_get_contents( $mimeTypeFile );
+                       } else {
+                               $this->logger->info( __METHOD__ . ": can't load mime types from $mimeTypeFile\n" );
+                       }
+               } else {
+                       $this->logger->info( __METHOD__ .
+                               ": no mime types file defined, using built-ins only.\n" );
+               }
+
+               $types .= "\n" . $this->extraTypes;
+
+               $types = str_replace( [ "\r\n", "\n\r", "\n\n", "\r\r", "\r" ], "\n", $types );
+               $types = str_replace( "\t", " ", $types );
+
+               $this->mimetoExt = [];
+               $this->mExtToMime = [];
+
+               $lines = explode( "\n", $types );
+               foreach ( $lines as $s ) {
+                       $s = trim( $s );
+                       if ( empty( $s ) ) {
+                               continue;
+                       }
+                       if ( strpos( $s, '#' ) === 0 ) {
+                               continue;
+                       }
+
+                       $s = strtolower( $s );
+                       $i = strpos( $s, ' ' );
+
+                       if ( $i === false ) {
+                               continue;
+                       }
+
+                       $mime = substr( $s, 0, $i );
+                       $ext = trim( substr( $s, $i + 1 ) );
+
+                       if ( empty( $ext ) ) {
+                               continue;
+                       }
+
+                       if ( !empty( $this->mimetoExt[$mime] ) ) {
+                               $this->mimetoExt[$mime] .= ' ' . $ext;
+                       } else {
+                               $this->mimetoExt[$mime] = $ext;
+                       }
+
+                       $extensions = explode( ' ', $ext );
+
+                       foreach ( $extensions as $e ) {
+                               $e = trim( $e );
+                               if ( empty( $e ) ) {
+                                       continue;
+                               }
+
+                               if ( !empty( $this->mExtToMime[$e] ) ) {
+                                       $this->mExtToMime[$e] .= ' ' . $mime;
+                               } else {
+                                       $this->mExtToMime[$e] = $mime;
+                               }
+                       }
+               }
+
+               /**
+                *   --- load mime.info ---
+                */
+
+               $mimeInfoFile = $this->infoFile;
+
+               $info = self::$wellKnownInfo;
+
+               if ( $mimeInfoFile ) {
+                       if ( is_file( $mimeInfoFile ) && is_readable( $mimeInfoFile ) ) {
+                               $this->logger->info( __METHOD__ . ": loading mime info from $mimeInfoFile\n" );
+                               $info .= "\n";
+                               $info .= file_get_contents( $mimeInfoFile );
+                       } else {
+                               $this->logger->info( __METHOD__ . ": can't load mime info from $mimeInfoFile\n" );
+                       }
+               } else {
+                       $this->logger->info( __METHOD__ .
+                               ": no mime info file defined, using built-ins only.\n" );
+               }
+
+               $info .= "\n" . $this->extraInfo;
+
+               $info = str_replace( [ "\r\n", "\n\r", "\n\n", "\r\r", "\r" ], "\n", $info );
+               $info = str_replace( "\t", " ", $info );
+
+               $this->mimeTypeAliases = [];
+               $this->mediaTypes = [];
+
+               $lines = explode( "\n", $info );
+               foreach ( $lines as $s ) {
+                       $s = trim( $s );
+                       if ( empty( $s ) ) {
+                               continue;
+                       }
+                       if ( strpos( $s, '#' ) === 0 ) {
+                               continue;
+                       }
+
+                       $s = strtolower( $s );
+                       $i = strpos( $s, ' ' );
+
+                       if ( $i === false ) {
+                               continue;
+                       }
+
+                       # print "processing MIME INFO line $s<br>";
+
+                       $match = [];
+                       if ( preg_match( '!\[\s*(\w+)\s*\]!', $s, $match ) ) {
+                               $s = preg_replace( '!\[\s*(\w+)\s*\]!', '', $s );
+                               $mtype = trim( strtoupper( $match[1] ) );
+                       } else {
+                               $mtype = MEDIATYPE_UNKNOWN;
+                       }
+
+                       $m = explode( ' ', $s );
+
+                       if ( !isset( $this->mediaTypes[$mtype] ) ) {
+                               $this->mediaTypes[$mtype] = [];
+                       }
+
+                       foreach ( $m as $mime ) {
+                               $mime = trim( $mime );
+                               if ( empty( $mime ) ) {
+                                       continue;
+                               }
+
+                               $this->mediaTypes[$mtype][] = $mime;
+                       }
+
+                       if ( count( $m ) > 1 ) {
+                               $main = $m[0];
+                               $mCount = count( $m );
+                               for ( $i = 1; $i < $mCount; $i += 1 ) {
+                                       $mime = $m[$i];
+                                       $this->mimeTypeAliases[$mime] = $main;
+                               }
+                       }
+               }
+       }
+
+       public function setLogger( LoggerInterface $logger ) {
+               $this->logger = $logger;
+       }
+
+       /**
+        * Adds to the list mapping MIME to file extensions.
+        * As an extension author, you are encouraged to submit patches to
+        * MediaWiki's core to add new MIME types to mime.types.
+        * @param string $types
+        */
+       public function addExtraTypes( $types ) {
+               $this->extraTypes .= "\n" . $types;
+       }
+
+       /**
+        * Adds to the list mapping MIME to media type.
+        * As an extension author, you are encouraged to submit patches to
+        * MediaWiki's core to add new MIME info to mime.info.
+        * @param string $info
+        */
+       public function addExtraInfo( $info ) {
+               $this->extraInfo .= "\n" . $info;
+       }
+
+       /**
+        * Returns a list of file extensions for a given MIME type as a space
+        * separated string or null if the MIME type was unrecognized. Resolves
+        * MIME type aliases.
+        *
+        * @param string $mime
+        * @return string|null
+        */
+       public function getExtensionsForType( $mime ) {
+               $mime = strtolower( $mime );
+
+               // Check the mime-to-ext map
+               if ( isset( $this->mimetoExt[$mime] ) ) {
+                       return $this->mimetoExt[$mime];
+               }
+
+               // Resolve the MIME type to the canonical type
+               if ( isset( $this->mimeTypeAliases[$mime] ) ) {
+                       $mime = $this->mimeTypeAliases[$mime];
+                       if ( isset( $this->mimetoExt[$mime] ) ) {
+                               return $this->mimetoExt[$mime];
+                       }
+               }
+
+               return null;
+       }
+
+       /**
+        * Returns a list of MIME types for a given file extension as a space
+        * separated string or null if the extension was unrecognized.
+        *
+        * @param string $ext
+        * @return string|null
+        */
+       public function getTypesForExtension( $ext ) {
+               $ext = strtolower( $ext );
+
+               $r = isset( $this->mExtToMime[$ext] ) ? $this->mExtToMime[$ext] : null;
+               return $r;
+       }
+
+       /**
+        * Returns a single MIME type for a given file extension or null if unknown.
+        * This is always the first type from the list returned by getTypesForExtension($ext).
+        *
+        * @param string $ext
+        * @return string|null
+        */
+       public function guessTypesForExtension( $ext ) {
+               $m = $this->getTypesForExtension( $ext );
+               if ( is_null( $m ) ) {
+                       return null;
+               }
+
+               // TODO: Check if this is needed; strtok( $m, ' ' ) should be sufficient
+               $m = trim( $m );
+               $m = preg_replace( '/\s.*$/', '', $m );
+
+               return $m;
+       }
+
+       /**
+        * Tests if the extension matches the given MIME type. Returns true if a
+        * match was found, null if the MIME type is unknown, and false if the
+        * MIME type is known but no matches where found.
+        *
+        * @param string $extension
+        * @param string $mime
+        * @return bool|null
+        */
+       public function isMatchingExtension( $extension, $mime ) {
+               $ext = $this->getExtensionsForType( $mime );
+
+               if ( !$ext ) {
+                       return null; // Unknown MIME type
+               }
+
+               $ext = explode( ' ', $ext );
+
+               $extension = strtolower( $extension );
+               return in_array( $extension, $ext );
+       }
+
+       /**
+        * Returns true if the MIME type is known to represent an image format
+        * supported by the PHP GD library.
+        *
+        * @param string $mime
+        *
+        * @return bool
+        */
+       public function isPHPImageType( $mime ) {
+               // As defined by imagegetsize and image_type_to_mime
+               static $types = [
+                       'image/gif', 'image/jpeg', 'image/png',
+                       'image/x-bmp', 'image/xbm', 'image/tiff',
+                       'image/jp2', 'image/jpeg2000', 'image/iff',
+                       'image/xbm', 'image/x-xbitmap',
+                       'image/vnd.wap.wbmp', 'image/vnd.xiff',
+                       'image/x-photoshop',
+                       'application/x-shockwave-flash',
+               ];
+
+               return in_array( $mime, $types );
+       }
+
+       /**
+        * Returns true if the extension represents a type which can
+        * be reliably detected from its content. Use this to determine
+        * whether strict content checks should be applied to reject
+        * invalid uploads; if we can't identify the type we won't
+        * be able to say if it's invalid.
+        *
+        * @todo Be more accurate when using fancy MIME detector plugins;
+        *       right now this is the bare minimum getimagesize() list.
+        * @param string $extension
+        * @return bool
+        */
+       function isRecognizableExtension( $extension ) {
+               static $types = [
+                       // Types recognized by getimagesize()
+                       'gif', 'jpeg', 'jpg', 'png', 'swf', 'psd',
+                       'bmp', 'tiff', 'tif', 'jpc', 'jp2',
+                       'jpx', 'jb2', 'swc', 'iff', 'wbmp',
+                       'xbm',
+
+                       // Formats we recognize magic numbers for
+                       'djvu', 'ogx', 'ogg', 'ogv', 'oga', 'spx',
+                       'mid', 'pdf', 'wmf', 'xcf', 'webm', 'mkv', 'mka',
+                       'webp',
+
+                       // XML formats we sure hope we recognize reliably
+                       'svg',
+               ];
+               return in_array( strtolower( $extension ), $types );
+       }
+
+       /**
+        * Improves a MIME type using the file extension. Some file formats are very generic,
+        * so their MIME type is not very meaningful. A more useful MIME type can be derived
+        * by looking at the file extension. Typically, this method would be called on the
+        * result of guessMimeType().
+        *
+        * @param string $mime The MIME type, typically guessed from a file's content.
+        * @param string $ext The file extension, as taken from the file name
+        *
+        * @return string The MIME type
+        */
+       public function improveTypeFromExtension( $mime, $ext ) {
+               if ( $mime === 'unknown/unknown' ) {
+                       if ( $this->isRecognizableExtension( $ext ) ) {
+                               $this->logger->info( __METHOD__ . ': refusing to guess mime type for .' .
+                                       "$ext file, we should have recognized it\n" );
+                       } else {
+                               // Not something we can detect, so simply
+                               // trust the file extension
+                               $mime = $this->guessTypesForExtension( $ext );
+                       }
+               } elseif ( $mime === 'application/x-opc+zip' ) {
+                       if ( $this->isMatchingExtension( $ext, $mime ) ) {
+                               // A known file extension for an OPC file,
+                               // find the proper MIME type for that file extension
+                               $mime = $this->guessTypesForExtension( $ext );
+                       } else {
+                               $this->logger->info( __METHOD__ .
+                                       ": refusing to guess better type for $mime file, " .
+                                       ".$ext is not a known OPC extension.\n" );
+                               $mime = 'application/zip';
+                       }
+               } elseif ( $mime === 'text/plain' && $this->findMediaType( ".$ext" ) === MEDIATYPE_TEXT ) {
+                       // Textual types are sometimes not recognized properly.
+                       // If detected as text/plain, and has an extension which is textual
+                       // improve to the extension's type. For example, csv and json are often
+                       // misdetected as text/plain.
+                       $mime = $this->guessTypesForExtension( $ext );
+               }
+
+               # Media handling extensions can improve the MIME detected
+               $callback = $this->extCallback;
+               if ( $callback ) {
+                       $callback( $this, $ext, $mime /* by reference */ );
+               }
+
+               if ( isset( $this->mimeTypeAliases[$mime] ) ) {
+                       $mime = $this->mimeTypeAliases[$mime];
+               }
+
+               $this->logger->info( __METHOD__ . ": improved mime type for .$ext: $mime\n" );
+               return $mime;
+       }
+
+       /**
+        * MIME type detection. This uses detectMimeType to detect the MIME type
+        * of the file, but applies additional checks to determine some well known
+        * file formats that may be missed or misinterpreted by the default MIME
+        * detection (namely XML based formats like XHTML or SVG, as well as ZIP
+        * based formats like OPC/ODF files).
+        *
+        * @param string $file The file to check
+        * @param string|bool $ext The file extension, or true (default) to extract
+        *   it from the filename. Set it to false to ignore the extension. DEPRECATED!
+        *   Set to false, use improveTypeFromExtension($mime, $ext) later to improve MIME type.
+        *
+        * @return string The MIME type of $file
+        */
+       public function guessMimeType( $file, $ext = true ) {
+               if ( $ext ) { // TODO: make $ext default to false. Or better, remove it.
+                       $this->logger->info( __METHOD__ .
+                               ": WARNING: use of the \$ext parameter is deprecated. " .
+                               "Use improveTypeFromExtension(\$mime, \$ext) instead.\n" );
+               }
+
+               $mime = $this->doGuessMimeType( $file, $ext );
+
+               if ( !$mime ) {
+                       $this->logger->info( __METHOD__ .
+                               ": internal type detection failed for $file (.$ext)...\n" );
+                       $mime = $this->detectMimeType( $file, $ext );
+               }
+
+               if ( isset( $this->mimeTypeAliases[$mime] ) ) {
+                       $mime = $this->mimeTypeAliases[$mime];
+               }
+
+               $this->logger->info( __METHOD__ . ": guessed mime type of $file: $mime\n" );
+               return $mime;
+       }
+
+       /**
+        * Guess the MIME type from the file contents.
+        *
+        * @todo Remove $ext param
+        *
+        * @param string $file
+        * @param mixed $ext
+        * @return bool|string
+        * @throws UnexpectedValueException
+        */
+       private function doGuessMimeType( $file, $ext ) {
+               // Read a chunk of the file
+               MediaWiki\suppressWarnings();
+               $f = fopen( $file, 'rb' );
+               MediaWiki\restoreWarnings();
+
+               if ( !$f ) {
+                       return 'unknown/unknown';
+               }
+
+               $fsize = filesize( $file );
+               if ( $fsize === false ) {
+                       return 'unknown/unknown';
+               }
+
+               $head = fread( $f, 1024 );
+               $tailLength = min( 65558, $fsize ); // 65558 = maximum size of a zip EOCDR
+               if ( fseek( $f, -1 * $tailLength, SEEK_END ) === -1 ) {
+                       throw new UnexpectedValueException(
+                               "Seeking $tailLength bytes from EOF failed in " . __METHOD__ );
+               }
+               $tail = $tailLength ? fread( $f, $tailLength ) : '';
+               fclose( $f );
+
+               $this->logger->info( __METHOD__ .
+                       ": analyzing head and tail of $file for magic numbers.\n" );
+
+               // Hardcode a few magic number checks...
+               $headers = [
+                       // Multimedia...
+                       'MThd'             => 'audio/midi',
+                       'OggS'             => 'application/ogg',
+
+                       // Image formats...
+                       // Note that WMF may have a bare header, no magic number.
+                       "\x01\x00\x09\x00" => 'application/x-msmetafile', // Possibly prone to false positives?
+                       "\xd7\xcd\xc6\x9a" => 'application/x-msmetafile',
+                       '%PDF'             => 'application/pdf',
+                       'gimp xcf'         => 'image/x-xcf',
+
+                       // Some forbidden fruit...
+                       'MZ'               => 'application/octet-stream', // DOS/Windows executable
+                       "\xca\xfe\xba\xbe" => 'application/octet-stream', // Mach-O binary
+                       "\x7fELF"          => 'application/octet-stream', // ELF binary
+               ];
+
+               foreach ( $headers as $magic => $candidate ) {
+                       if ( strncmp( $head, $magic, strlen( $magic ) ) == 0 ) {
+                               $this->logger->info( __METHOD__ .
+                                       ": magic header in $file recognized as $candidate\n" );
+                               return $candidate;
+                       }
+               }
+
+               /* Look for WebM and Matroska files */
+               if ( strncmp( $head, pack( "C4", 0x1a, 0x45, 0xdf, 0xa3 ), 4 ) == 0 ) {
+                       $doctype = strpos( $head, "\x42\x82" );
+                       if ( $doctype ) {
+                               // Next byte is datasize, then data (sizes larger than 1 byte are stupid muxers)
+                               $data = substr( $head, $doctype + 3, 8 );
+                               if ( strncmp( $data, "matroska", 8 ) == 0 ) {
+                                       $this->logger->info( __METHOD__ . ": recognized file as video/x-matroska\n" );
+                                       return "video/x-matroska";
+                               } elseif ( strncmp( $data, "webm", 4 ) == 0 ) {
+                                       $this->logger->info( __METHOD__ . ": recognized file as video/webm\n" );
+                                       return "video/webm";
+                               }
+                       }
+                       $this->logger->info( __METHOD__ . ": unknown EBML file\n" );
+                       return "unknown/unknown";
+               }
+
+               /* Look for WebP */
+               if ( strncmp( $head, "RIFF", 4 ) == 0 &&
+                       strncmp( substr( $head, 8, 7 ), "WEBPVP8", 7 ) == 0
+               ) {
+                       $this->logger->info( __METHOD__ . ": recognized file as image/webp\n" );
+                       return "image/webp";
+               }
+
+               /**
+                * Look for PHP.  Check for this before HTML/XML...  Warning: this is a
+                * heuristic, and won't match a file with a lot of non-PHP before.  It
+                * will also match text files which could be PHP. :)
+                *
+                * @todo FIXME: For this reason, the check is probably useless -- an attacker
+                * could almost certainly just pad the file with a lot of nonsense to
+                * circumvent the check in any case where it would be a security
+                * problem.  On the other hand, it causes harmful false positives (bug
+                * 16583).  The heuristic has been cut down to exclude three-character
+                * strings like "<? ", but should it be axed completely?
+                */
+               if ( ( strpos( $head, '<?php' ) !== false ) ||
+                       ( strpos( $head, "<\x00?\x00p\x00h\x00p" ) !== false ) ||
+                       ( strpos( $head, "<\x00?\x00 " ) !== false ) ||
+                       ( strpos( $head, "<\x00?\x00\n" ) !== false ) ||
+                       ( strpos( $head, "<\x00?\x00\t" ) !== false ) ||
+                       ( strpos( $head, "<\x00?\x00=" ) !== false ) ) {
+
+                       $this->logger->info( __METHOD__ . ": recognized $file as application/x-php\n" );
+                       return 'application/x-php';
+               }
+
+               /**
+                * look for XML formats (XHTML and SVG)
+                */
+               $xml = new XmlTypeCheck( $file );
+               if ( $xml->wellFormed ) {
+                       $xmlTypes = $this->xmlTypes;
+                       if ( isset( $xmlTypes[$xml->getRootElement()] ) ) {
+                               return $xmlTypes[$xml->getRootElement()];
+                       } else {
+                               return 'application/xml';
+                       }
+               }
+
+               /**
+                * look for shell scripts
+                */
+               $script_type = null;
+
+               # detect by shebang
+               if ( substr( $head, 0, 2 ) == "#!" ) {
+                       $script_type = "ASCII";
+               } elseif ( substr( $head, 0, 5 ) == "\xef\xbb\xbf#!" ) {
+                       $script_type = "UTF-8";
+               } elseif ( substr( $head, 0, 7 ) == "\xfe\xff\x00#\x00!" ) {
+                       $script_type = "UTF-16BE";
+               } elseif ( substr( $head, 0, 7 ) == "\xff\xfe#\x00!" ) {
+                       $script_type = "UTF-16LE";
+               }
+
+               if ( $script_type ) {
+                       if ( $script_type !== "UTF-8" && $script_type !== "ASCII" ) {
+                               // Quick and dirty fold down to ASCII!
+                               $pack = [ 'UTF-16BE' => 'n*', 'UTF-16LE' => 'v*' ];
+                               $chars = unpack( $pack[$script_type], substr( $head, 2 ) );
+                               $head = '';
+                               foreach ( $chars as $codepoint ) {
+                                       if ( $codepoint < 128 ) {
+                                               $head .= chr( $codepoint );
+                                       } else {
+                                               $head .= '?';
+                                       }
+                               }
+                       }
+
+                       $match = [];
+
+                       if ( preg_match( '%/?([^\s]+/)(\w+)%', $head, $match ) ) {
+                               $mime = "application/x-{$match[2]}";
+                               $this->logger->info( __METHOD__ . ": shell script recognized as $mime\n" );
+                               return $mime;
+                       }
+               }
+
+               // Check for ZIP variants (before getimagesize)
+               if ( strpos( $tail, "PK\x05\x06" ) !== false ) {
+                       $this->logger->info( __METHOD__ . ": ZIP header present in $file\n" );
+                       return $this->detectZipType( $head, $tail, $ext );
+               }
+
+               MediaWiki\suppressWarnings();
+               $gis = getimagesize( $file );
+               MediaWiki\restoreWarnings();
+
+               if ( $gis && isset( $gis['mime'] ) ) {
+                       $mime = $gis['mime'];
+                       $this->logger->info( __METHOD__ . ": getimagesize detected $file as $mime\n" );
+                       return $mime;
+               }
+
+               # Media handling extensions can guess the MIME by content
+               # It's intentionally here so that if core is wrong about a type (false positive),
+               # people will hopefully nag and submit patches :)
+               $mime = false;
+               # Some strings by reference for performance - assuming well-behaved hooks
+               $callback = $this->guessCallback;
+               if ( $callback ) {
+                       $callback( $this, $head, $tail, $file, $mime /* by reference */ );
+               };
+
+               return $mime;
+       }
+
+       /**
+        * Detect application-specific file type of a given ZIP file from its
+        * header data.  Currently works for OpenDocument and OpenXML types...
+        * If can't tell, returns 'application/zip'.
+        *
+        * @param string $header Some reasonably-sized chunk of file header
+        * @param string|null $tail The tail of the file
+        * @param string|bool $ext The file extension, or true to extract it from the filename.
+        *   Set it to false (default) to ignore the extension. DEPRECATED! Set to false,
+        *   use improveTypeFromExtension($mime, $ext) later to improve MIME type.
+        *
+        * @return string
+        */
+       function detectZipType( $header, $tail = null, $ext = false ) {
+               if ( $ext ) { # TODO: remove $ext param
+                       $this->logger->info( __METHOD__ .
+                               ": WARNING: use of the \$ext parameter is deprecated. " .
+                               "Use improveTypeFromExtension(\$mime, \$ext) instead.\n" );
+               }
+
+               $mime = 'application/zip';
+               $opendocTypes = [
+                       'chart-template',
+                       'chart',
+                       'formula-template',
+                       'formula',
+                       'graphics-template',
+                       'graphics',
+                       'image-template',
+                       'image',
+                       'presentation-template',
+                       'presentation',
+                       'spreadsheet-template',
+                       'spreadsheet',
+                       'text-template',
+                       'text-master',
+                       'text-web',
+                       'text' ];
+
+               // http://lists.oasis-open.org/archives/office/200505/msg00006.html
+               $types = '(?:' . implode( '|', $opendocTypes ) . ')';
+               $opendocRegex = "/^mimetype(application\/vnd\.oasis\.opendocument\.$types)/";
+
+               $openxmlRegex = "/^\[Content_Types\].xml/";
+
+               if ( preg_match( $opendocRegex, substr( $header, 30 ), $matches ) ) {
+                       $mime = $matches[1];
+                       $this->logger->info( __METHOD__ . ": detected $mime from ZIP archive\n" );
+               } elseif ( preg_match( $openxmlRegex, substr( $header, 30 ) ) ) {
+                       $mime = "application/x-opc+zip";
+                       # TODO: remove the block below, as soon as improveTypeFromExtension is used everywhere
+                       if ( $ext !== true && $ext !== false ) {
+                               /** This is the mode used by getPropsFromPath
+                                * These MIME's are stored in the database, where we don't really want
+                                * x-opc+zip, because we use it only for internal purposes
+                                */
+                               if ( $this->isMatchingExtension( $ext, $mime ) ) {
+                                       /* A known file extension for an OPC file,
+                                        * find the proper mime type for that file extension
+                                        */
+                                       $mime = $this->guessTypesForExtension( $ext );
+                               } else {
+                                       $mime = "application/zip";
+                               }
+                       }
+                       $this->logger->info( __METHOD__ .
+                               ": detected an Open Packaging Conventions archive: $mime\n" );
+               } elseif ( substr( $header, 0, 8 ) == "\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1" &&
+                       ( $headerpos = strpos( $tail, "PK\x03\x04" ) ) !== false &&
+                       preg_match( $openxmlRegex, substr( $tail, $headerpos + 30 ) ) ) {
+                       if ( substr( $header, 512, 4 ) == "\xEC\xA5\xC1\x00" ) {
+                               $mime = "application/msword";
+                       }
+                       switch ( substr( $header, 512, 6 ) ) {
+                               case "\xEC\xA5\xC1\x00\x0E\x00":
+                               case "\xEC\xA5\xC1\x00\x1C\x00":
+                               case "\xEC\xA5\xC1\x00\x43\x00":
+                                       $mime = "application/vnd.ms-powerpoint";
+                                       break;
+                               case "\xFD\xFF\xFF\xFF\x10\x00":
+                               case "\xFD\xFF\xFF\xFF\x1F\x00":
+                               case "\xFD\xFF\xFF\xFF\x22\x00":
+                               case "\xFD\xFF\xFF\xFF\x23\x00":
+                               case "\xFD\xFF\xFF\xFF\x28\x00":
+                               case "\xFD\xFF\xFF\xFF\x29\x00":
+                               case "\xFD\xFF\xFF\xFF\x10\x02":
+                               case "\xFD\xFF\xFF\xFF\x1F\x02":
+                               case "\xFD\xFF\xFF\xFF\x22\x02":
+                               case "\xFD\xFF\xFF\xFF\x23\x02":
+                               case "\xFD\xFF\xFF\xFF\x28\x02":
+                               case "\xFD\xFF\xFF\xFF\x29\x02":
+                                       $mime = "application/vnd.msexcel";
+                                       break;
+                       }
+
+                       $this->logger->info( __METHOD__ .
+                               ": detected a MS Office document with OPC trailer\n" );
+               } else {
+                       $this->logger->info( __METHOD__ . ": unable to identify type of ZIP archive\n" );
+               }
+               return $mime;
+       }
+
+       /**
+        * Internal MIME type detection. Detection is done using the fileinfo
+        * extension if it is available. It can be overriden by callback, which could
+        * use an external program, for example. If detection fails and $ext is not false,
+        * the MIME type is guessed from the file extension, using guessTypesForExtension.
+        *
+        * If the MIME type is still unknown, getimagesize is used to detect the
+        * MIME type if the file is an image. If no MIME type can be determined,
+        * this function returns 'unknown/unknown'.
+        *
+        * @param string $file The file to check
+        * @param string|bool $ext The file extension, or true (default) to extract it from the filename.
+        *   Set it to false to ignore the extension. DEPRECATED! Set to false, use
+        *   improveTypeFromExtension($mime, $ext) later to improve MIME type.
+        *
+        * @return string The MIME type of $file
+        */
+       private function detectMimeType( $file, $ext = true ) {
+               /** @todo Make $ext default to false. Or better, remove it. */
+               if ( $ext ) {
+                       $this->logger->info( __METHOD__ .
+                               ": WARNING: use of the \$ext parameter is deprecated. "
+                               . "Use improveTypeFromExtension(\$mime, \$ext) instead.\n" );
+               }
+
+               $callback = $this->detectCallback;
+               $m = null;
+               if ( $callback ) {
+                       $m = $callback( $file );
+               } elseif ( function_exists( "finfo_open" ) && function_exists( "finfo_file" ) ) {
+                       $mime_magic_resource = finfo_open( FILEINFO_MIME );
+
+                       if ( $mime_magic_resource ) {
+                               $m = finfo_file( $mime_magic_resource, $file );
+                               finfo_close( $mime_magic_resource );
+                       } else {
+                               $this->logger->info( __METHOD__ .
+                                       ": finfo_open failed on " . FILEINFO_MIME . "!\n" );
+                       }
+               } else {
+                       $this->logger->info( __METHOD__ . ": no magic mime detector found!\n" );
+               }
+
+               if ( $m ) {
+                       # normalize
+                       $m = preg_replace( '![;, ].*$!', '', $m ); # strip charset, etc
+                       $m = trim( $m );
+                       $m = strtolower( $m );
+
+                       if ( strpos( $m, 'unknown' ) !== false ) {
+                               $m = null;
+                       } else {
+                               $this->logger->info( __METHOD__ . ": magic mime type of $file: $m\n" );
+                               return $m;
+                       }
+               }
+
+               // If desired, look at extension as a fallback.
+               if ( $ext === true ) {
+                       $i = strrpos( $file, '.' );
+                       $ext = strtolower( $i ? substr( $file, $i + 1 ) : '' );
+               }
+               if ( $ext ) {
+                       if ( $this->isRecognizableExtension( $ext ) ) {
+                               $this->logger->info( __METHOD__ . ": refusing to guess mime type for .$ext file, "
+                                       . "we should have recognized it\n" );
+                       } else {
+                               $m = $this->guessTypesForExtension( $ext );
+                               if ( $m ) {
+                                       $this->logger->info( __METHOD__ . ": extension mime type of $file: $m\n" );
+                                       return $m;
+                               }
+                       }
+               }
+
+               // Unknown type
+               $this->logger->info( __METHOD__ . ": failed to guess mime type for $file!\n" );
+               return 'unknown/unknown';
+       }
+
+       /**
+        * Determine the media type code for a file, using its MIME type, name and
+        * possibly its contents.
+        *
+        * This function relies on the findMediaType(), mapping extensions and MIME
+        * types to media types.
+        *
+        * @todo analyse file if need be
+        * @todo look at multiple extension, separately and together.
+        *
+        * @param string $path Full path to the image file, in case we have to look at the contents
+        *        (if null, only the MIME type is used to determine the media type code).
+        * @param string $mime MIME type. If null it will be guessed using guessMimeType.
+        *
+        * @return string A value to be used with the MEDIATYPE_xxx constants.
+        */
+       function getMediaType( $path = null, $mime = null ) {
+               if ( !$mime && !$path ) {
+                       return MEDIATYPE_UNKNOWN;
+               }
+
+               // If MIME type is unknown, guess it
+               if ( !$mime ) {
+                       $mime = $this->guessMimeType( $path, false );
+               }
+
+               // Special code for ogg - detect if it's video (theora),
+               // else label it as sound.
+               if ( $mime == 'application/ogg' && file_exists( $path ) ) {
+
+                       // Read a chunk of the file
+                       $f = fopen( $path, "rt" );
+                       if ( !$f ) {
+                               return MEDIATYPE_UNKNOWN;
+                       }
+                       $head = fread( $f, 256 );
+                       fclose( $f );
+
+                       $head = str_replace( 'ffmpeg2theora', '', strtolower( $head ) );
+
+                       // This is an UGLY HACK, file should be parsed correctly
+                       if ( strpos( $head, 'theora' ) !== false ) {
+                               return MEDIATYPE_VIDEO;
+                       } elseif ( strpos( $head, 'vorbis' ) !== false ) {
+                               return MEDIATYPE_AUDIO;
+                       } elseif ( strpos( $head, 'flac' ) !== false ) {
+                               return MEDIATYPE_AUDIO;
+                       } elseif ( strpos( $head, 'speex' ) !== false ) {
+                               return MEDIATYPE_AUDIO;
+                       } else {
+                               return MEDIATYPE_MULTIMEDIA;
+                       }
+               }
+
+               $type = null;
+               // Check for entry for full MIME type
+               if ( $mime ) {
+                       $type = $this->findMediaType( $mime );
+                       if ( $type !== MEDIATYPE_UNKNOWN ) {
+                               return $type;
+                       }
+               }
+
+               // Check for entry for file extension
+               if ( $path ) {
+                       $i = strrpos( $path, '.' );
+                       $e = strtolower( $i ? substr( $path, $i + 1 ) : '' );
+
+                       // TODO: look at multi-extension if this fails, parse from full path
+                       $type = $this->findMediaType( '.' . $e );
+                       if ( $type !== MEDIATYPE_UNKNOWN ) {
+                               return $type;
+                       }
+               }
+
+               // Check major MIME type
+               if ( $mime ) {
+                       $i = strpos( $mime, '/' );
+                       if ( $i !== false ) {
+                               $major = substr( $mime, 0, $i );
+                               $type = $this->findMediaType( $major );
+                               if ( $type !== MEDIATYPE_UNKNOWN ) {
+                                       return $type;
+                               }
+                       }
+               }
+
+               if ( !$type ) {
+                       $type = MEDIATYPE_UNKNOWN;
+               }
+
+               return $type;
+       }
+
+       /**
+        * Returns a media code matching the given MIME type or file extension.
+        * File extensions are represented by a string starting with a dot (.) to
+        * distinguish them from MIME types.
+        *
+        * This function relies on the mapping defined by $this->mMediaTypes
+        * @access private
+        * @param string $extMime
+        * @return int|string
+        */
+       function findMediaType( $extMime ) {
+               if ( strpos( $extMime, '.' ) === 0 ) {
+                       // If it's an extension, look up the MIME types
+                       $m = $this->getTypesForExtension( substr( $extMime, 1 ) );
+                       if ( !$m ) {
+                               return MEDIATYPE_UNKNOWN;
+                       }
+
+                       $m = explode( ' ', $m );
+               } else {
+                       // Normalize MIME type
+                       if ( isset( $this->mimeTypeAliases[$extMime] ) ) {
+                               $extMime = $this->mimeTypeAliases[$extMime];
+                       }
+
+                       $m = [ $extMime ];
+               }
+
+               foreach ( $m as $mime ) {
+                       foreach ( $this->mediaTypes as $type => $codes ) {
+                               if ( in_array( $mime, $codes, true ) ) {
+                                       return $type;
+                               }
+                       }
+               }
+
+               return MEDIATYPE_UNKNOWN;
+       }
+
+       /**
+        * Get the MIME types that various versions of Internet Explorer would
+        * detect from a chunk of the content.
+        *
+        * @param string $fileName The file name (unused at present)
+        * @param string $chunk The first 256 bytes of the file
+        * @param string $proposed The MIME type proposed by the server
+        * @return array
+        */
+       public function getIEMimeTypes( $fileName, $chunk, $proposed ) {
+               $ca = $this->getIEContentAnalyzer();
+               return $ca->getRealMimesFromData( $fileName, $chunk, $proposed );
+       }
+
+       /**
+        * Get a cached instance of IEContentAnalyzer
+        *
+        * @return IEContentAnalyzer
+        */
+       protected function getIEContentAnalyzer() {
+               if ( is_null( $this->IEAnalyzer ) ) {
+                       $this->IEAnalyzer = new IEContentAnalyzer;
+               }
+               return $this->IEAnalyzer;
+       }
+}
diff --git a/includes/libs/mime/XmlTypeCheck.php b/includes/libs/mime/XmlTypeCheck.php
new file mode 100644 (file)
index 0000000..f057140
--- /dev/null
@@ -0,0 +1,347 @@
+<?php
+/**
+ * XML syntax and type checker.
+ *
+ * Since 1.24.2, it uses XMLReader instead of xml_parse, which gives us
+ * more control over the expansion of XML entities. When passed to the
+ * callback, entities will be fully expanded, but may report the XML is
+ * invalid if expanding the entities are likely to cause a DoS.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+class XmlTypeCheck {
+       /**
+        * Will be set to true or false to indicate whether the file is
+        * well-formed XML. Note that this doesn't check schema validity.
+        */
+       public $wellFormed = null;
+
+       /**
+        * Will be set to true if the optional element filter returned
+        * a match at some point.
+        */
+       public $filterMatch = false;
+
+       /**
+        * Will contain the type of filter hit if the optional element filter returned
+        * a match at some point.
+        * @var mixed
+        */
+       public $filterMatchType = false;
+
+       /**
+        * Name of the document's root element, including any namespace
+        * as an expanded URL.
+        */
+       public $rootElement = '';
+
+       /**
+        * A stack of strings containing the data of each xml element as it's processed. Append
+        * data to the top string of the stack, then pop off the string and process it when the
+        * element is closed.
+        */
+       protected $elementData = [];
+
+       /**
+        * A stack of element names and attributes, as we process them.
+        */
+       protected $elementDataContext = [];
+
+       /**
+        * Current depth of the data stack.
+        */
+       protected $stackDepth = 0;
+
+       /**
+        * Additional parsing options
+        */
+       private $parserOptions = [
+               'processing_instruction_handler' => '',
+       ];
+
+       /**
+        * @param string $input a filename or string containing the XML element
+        * @param callable $filterCallback (optional)
+        *        Function to call to do additional custom validity checks from the
+        *        SAX element handler event. This gives you access to the element
+        *        namespace, name, attributes, and text contents.
+        *        Filter should return 'true' to toggle on $this->filterMatch
+        * @param bool $isFile (optional) indicates if the first parameter is a
+        *        filename (default, true) or if it is a string (false)
+        * @param array $options list of additional parsing options:
+        *        processing_instruction_handler: Callback for xml_set_processing_instruction_handler
+        */
+       function __construct( $input, $filterCallback = null, $isFile = true, $options = [] ) {
+               $this->filterCallback = $filterCallback;
+               $this->parserOptions = array_merge( $this->parserOptions, $options );
+               $this->validateFromInput( $input, $isFile );
+       }
+
+       /**
+        * Alternative constructor: from filename
+        *
+        * @param string $fname the filename of an XML document
+        * @param callable $filterCallback (optional)
+        *        Function to call to do additional custom validity checks from the
+        *        SAX element handler event. This gives you access to the element
+        *        namespace, name, and attributes, but not to text contents.
+        *        Filter should return 'true' to toggle on $this->filterMatch
+        * @return XmlTypeCheck
+        */
+       public static function newFromFilename( $fname, $filterCallback = null ) {
+               return new self( $fname, $filterCallback, true );
+       }
+
+       /**
+        * Alternative constructor: from string
+        *
+        * @param string $string a string containing an XML element
+        * @param callable $filterCallback (optional)
+        *        Function to call to do additional custom validity checks from the
+        *        SAX element handler event. This gives you access to the element
+        *        namespace, name, and attributes, but not to text contents.
+        *        Filter should return 'true' to toggle on $this->filterMatch
+        * @return XmlTypeCheck
+        */
+       public static function newFromString( $string, $filterCallback = null ) {
+               return new self( $string, $filterCallback, false );
+       }
+
+       /**
+        * Get the root element. Simple accessor to $rootElement
+        *
+        * @return string
+        */
+       public function getRootElement() {
+               return $this->rootElement;
+       }
+
+       /**
+        * @param string $fname the filename
+        */
+       private function validateFromInput( $xml, $isFile ) {
+               $reader = new XMLReader();
+               if ( $isFile ) {
+                       $s = $reader->open( $xml, null, LIBXML_NOERROR | LIBXML_NOWARNING );
+               } else {
+                       $s = $reader->XML( $xml, null, LIBXML_NOERROR | LIBXML_NOWARNING );
+               }
+               if ( $s !== true ) {
+                       // Couldn't open the XML
+                       $this->wellFormed = false;
+               } else {
+                       $oldDisable = libxml_disable_entity_loader( true );
+                       $reader->setParserProperty( XMLReader::SUBST_ENTITIES, true );
+                       try {
+                               $this->validate( $reader );
+                       } catch ( Exception $e ) {
+                               // Calling this malformed, because we didn't parse the whole
+                               // thing. Maybe just an external entity refernce.
+                               $this->wellFormed = false;
+                               $reader->close();
+                               libxml_disable_entity_loader( $oldDisable );
+                               throw $e;
+                       }
+                       $reader->close();
+                       libxml_disable_entity_loader( $oldDisable );
+               }
+       }
+
+       private function readNext( XMLReader $reader ) {
+               set_error_handler( [ $this, 'XmlErrorHandler' ] );
+               $ret = $reader->read();
+               restore_error_handler();
+               return $ret;
+       }
+
+       public function XmlErrorHandler( $errno, $errstr ) {
+               $this->wellFormed = false;
+       }
+
+       private function validate( $reader ) {
+
+               // First, move through anything that isn't an element, and
+               // handle any processing instructions with the callback
+               do {
+                       if ( !$this->readNext( $reader ) ) {
+                               // Hit the end of the document before any elements
+                               $this->wellFormed = false;
+                               return;
+                       }
+                       if ( $reader->nodeType === XMLReader::PI ) {
+                               $this->processingInstructionHandler( $reader->name, $reader->value );
+                       }
+               } while ( $reader->nodeType != XMLReader::ELEMENT );
+
+               // Process the rest of the document
+               do {
+                       switch ( $reader->nodeType ) {
+                               case XMLReader::ELEMENT:
+                                       $name = $this->expandNS(
+                                               $reader->name,
+                                               $reader->namespaceURI
+                                       );
+                                       if ( $this->rootElement === '' ) {
+                                               $this->rootElement = $name;
+                                       }
+                                       $empty = $reader->isEmptyElement;
+                                       $attrs = $this->getAttributesArray( $reader );
+                                       $this->elementOpen( $name, $attrs );
+                                       if ( $empty ) {
+                                               $this->elementClose();
+                                       }
+                                       break;
+
+                               case XMLReader::END_ELEMENT:
+                                       $this->elementClose();
+                                       break;
+
+                               case XMLReader::WHITESPACE:
+                               case XMLReader::SIGNIFICANT_WHITESPACE:
+                               case XMLReader::CDATA:
+                               case XMLReader::TEXT:
+                                       $this->elementData( $reader->value );
+                                       break;
+
+                               case XMLReader::ENTITY_REF:
+                                       // Unexpanded entity (maybe external?),
+                                       // don't send to the filter (xml_parse didn't)
+                                       break;
+
+                               case XMLReader::COMMENT:
+                                       // Don't send to the filter (xml_parse didn't)
+                                       break;
+
+                               case XMLReader::PI:
+                                       // Processing instructions can happen after the header too
+                                       $this->processingInstructionHandler(
+                                               $reader->name,
+                                               $reader->value
+                                       );
+                                       break;
+                               default:
+                                       // One of DOC, DOC_TYPE, ENTITY, END_ENTITY,
+                                       // NOTATION, or XML_DECLARATION
+                                       // xml_parse didn't send these to the filter, so we won't.
+                       }
+
+               } while ( $this->readNext( $reader ) );
+
+               if ( $this->stackDepth !== 0 ) {
+                       $this->wellFormed = false;
+               } elseif ( $this->wellFormed === null ) {
+                       $this->wellFormed = true;
+               }
+
+       }
+
+       /**
+        * Get all of the attributes for an XMLReader's current node
+        * @param $r XMLReader
+        * @return array of attributes
+        */
+       private function getAttributesArray( XMLReader $r ) {
+               $attrs = [];
+               while ( $r->moveToNextAttribute() ) {
+                       if ( $r->namespaceURI === 'http://www.w3.org/2000/xmlns/' ) {
+                               // XMLReader treats xmlns attributes as normal
+                               // attributes, while xml_parse doesn't
+                               continue;
+                       }
+                       $name = $this->expandNS( $r->name, $r->namespaceURI );
+                       $attrs[$name] = $r->value;
+               }
+               return $attrs;
+       }
+
+       /**
+        * @param $name element or attribute name, maybe with a full or short prefix
+        * @param $namespaceURI the namespaceURI
+        * @return string the name prefixed with namespaceURI
+        */
+       private function expandNS( $name, $namespaceURI ) {
+               if ( $namespaceURI ) {
+                       $parts = explode( ':', $name );
+                       $localname = array_pop( $parts );
+                       return "$namespaceURI:$localname";
+               }
+               return $name;
+       }
+
+       /**
+        * @param $name
+        * @param $attribs
+        */
+       private function elementOpen( $name, $attribs ) {
+               $this->elementDataContext[] = [ $name, $attribs ];
+               $this->elementData[] = '';
+               $this->stackDepth++;
+       }
+
+       /**
+        */
+       private function elementClose() {
+               list( $name, $attribs ) = array_pop( $this->elementDataContext );
+               $data = array_pop( $this->elementData );
+               $this->stackDepth--;
+               $callbackReturn = false;
+
+               if ( is_callable( $this->filterCallback ) ) {
+                       $callbackReturn = call_user_func(
+                               $this->filterCallback,
+                               $name,
+                               $attribs,
+                               $data
+                       );
+               }
+               if ( $callbackReturn ) {
+                       // Filter hit!
+                       $this->filterMatch = true;
+                       $this->filterMatchType = $callbackReturn;
+               }
+       }
+
+       /**
+        * @param $data
+        */
+       private function elementData( $data ) {
+               // Collect any data here, and we'll run the callback in elementClose
+               $this->elementData[ $this->stackDepth - 1 ] .= trim( $data );
+       }
+
+       /**
+        * @param $target
+        * @param $data
+        */
+       private function processingInstructionHandler( $target, $data ) {
+               $callbackReturn = false;
+               if ( $this->parserOptions['processing_instruction_handler'] ) {
+                       $callbackReturn = call_user_func(
+                               $this->parserOptions['processing_instruction_handler'],
+                               $target,
+                               $data
+                       );
+               }
+               if ( $callbackReturn ) {
+                       // Filter hit!
+                       $this->filterMatch = true;
+                       $this->filterMatchType = $callbackReturn;
+               }
+       }
+}
diff --git a/includes/libs/mime/defines.php b/includes/libs/mime/defines.php
new file mode 100644 (file)
index 0000000..ae0b5f8
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**@{
+ * Media types.
+ * This defines constants for the value returned by File::getMediaType()
+ */
+// unknown format
+define( 'MEDIATYPE_UNKNOWN', 'UNKNOWN' );
+// some bitmap image or image source (like psd, etc). Can't scale up.
+define( 'MEDIATYPE_BITMAP', 'BITMAP' );
+// some vector drawing (SVG, WMF, PS, ...) or image source (oo-draw, etc). Can scale up.
+define( 'MEDIATYPE_DRAWING', 'DRAWING' );
+// simple audio file (ogg, mp3, wav, midi, whatever)
+define( 'MEDIATYPE_AUDIO', 'AUDIO' );
+// simple video file (ogg, mpg, etc;
+// no not include formats here that may contain executable sections or scripts!)
+define( 'MEDIATYPE_VIDEO', 'VIDEO' );
+// Scriptable Multimedia (flash, advanced video container formats, etc)
+define( 'MEDIATYPE_MULTIMEDIA', 'MULTIMEDIA' );
+// Office Documents, Spreadsheets (office formats possibly containing apples, scripts, etc)
+define( 'MEDIATYPE_OFFICE', 'OFFICE' );
+// Plain text (possibly containing program code or scripts)
+define( 'MEDIATYPE_TEXT', 'TEXT' );
+// binary executable
+define( 'MEDIATYPE_EXECUTABLE', 'EXECUTABLE' );
+// archive file (zip, tar, etc)
+define( 'MEDIATYPE_ARCHIVE', 'ARCHIVE' );
+/**@}*/
diff --git a/includes/libs/mime/mime.info b/includes/libs/mime/mime.info
new file mode 100644 (file)
index 0000000..b04d3c6
--- /dev/null
@@ -0,0 +1,119 @@
+# MIME type info file.
+# the first MIME type in each line is the "main" MIME type,
+# the others are aliases for this type
+# the media type is given in upper case and square brackets,
+# like [BITMAP], and must indicate a media type as defined by
+# the MEDIATYPE_xxx constants in Defines.php
+
+
+image/gif      [BITMAP]
+image/png image/x-png  [BITMAP]
+image/ief      [BITMAP]
+image/jpeg image/pjpeg [BITMAP]
+image/jp2      [BITMAP]
+image/xbm      [BITMAP]
+image/tiff     [BITMAP]
+image/x-icon image/x-ico image/vnd.microsoft.icon      [BITMAP]
+image/x-rgb    [BITMAP]
+image/x-portable-pixmap                [BITMAP]
+image/x-portable-graymap image/x-portable-greymap      [BITMAP]
+image/x-bmp image/x-ms-bmp image/bmp application/x-bmp application/bmp [BITMAP]
+image/x-photoshop image/psd image/x-psd image/photoshop image/vnd.adobe.photoshop      [BITMAP]
+image/vnd.djvu image/x.djvu image/x-djvu [BITMAP]
+image/webp     [BITMAP]
+
+image/svg+xml application/svg+xml application/svg image/svg    [DRAWING]
+application/postscript [DRAWING]
+application/x-latex    [DRAWING]
+application/x-tex      [DRAWING]
+application/x-dia-diagram [DRAWING]
+
+
+audio/mpeg audio/mp3 audio/mpeg3       [AUDIO]
+audio/mp4                              [AUDIO]
+audio/wav audio/x-wav audio/wave       [AUDIO]
+audio/midi audio/mid   [AUDIO]
+audio/basic            [AUDIO]
+audio/ogg              [AUDIO]
+audio/x-aiff           [AUDIO]
+audio/x-pn-realaudio   [AUDIO]
+audio/x-realaudio      [AUDIO]
+audio/webm             [AUDIO]
+audio/x-matroska       [AUDIO]
+audio/x-flac           [AUDIO]
+audio/flac             [AUDIO]
+
+video/mpeg application/mpeg    [VIDEO]
+video/ogg                      [VIDEO]
+video/x-sgi-video              [VIDEO]
+video/x-flv                    [VIDEO]
+video/webm                     [VIDEO]
+video/x-matroska               [VIDEO]
+video/mp4                      [VIDEO]
+
+application/ogg application/x-ogg audio/ogg audio/x-ogg video/ogg video/x-ogg          [MULTIMEDIA]
+
+application/x-shockwave-flash  [MULTIMEDIA]
+audio/x-pn-realaudio-plugin    [MULTIMEDIA]
+model/iges     [MULTIMEDIA]
+model/mesh     [MULTIMEDIA]
+model/vrml     [MULTIMEDIA]
+video/quicktime        [MULTIMEDIA]
+video/x-msvideo        [MULTIMEDIA]
+
+text/plain     [TEXT]
+text/html application/xhtml+xml        [TEXT]
+application/xml text/xml       [TEXT]
+text   [TEXT]
+application/json       [TEXT]
+text/csv       [TEXT]
+text/tab-separated-values      [TEXT]
+
+application/zip application/x-zip      [ARCHIVE]
+application/x-gzip     [ARCHIVE]
+application/x-bzip     [ARCHIVE]
+application/x-bzip2    [ARCHIVE]
+application/x-tar      [ARCHIVE]
+application/x-stuffit  [ARCHIVE]
+application/x-opc+zip  [ARCHIVE]
+application/x-7z-compressed [ARCHIVE]
+
+application/javascript text/javascript application/x-javascript application/x-ecmascript text/ecmascript       [EXECUTABLE]
+application/x-bash     [EXECUTABLE]
+application/x-sh       [EXECUTABLE]
+application/x-csh      [EXECUTABLE]
+application/x-tcsh     [EXECUTABLE]
+application/x-tcl      [EXECUTABLE]
+application/x-perl     [EXECUTABLE]
+application/x-python   [EXECUTABLE]
+
+application/pdf application/acrobat    [OFFICE]
+application/msword             [OFFICE]
+application/vnd.ms-excel       [OFFICE]
+application/vnd.ms-powerpoint  [OFFICE]
+application/x-director         [OFFICE]
+text/rtf                       [OFFICE]
+
+application/vnd.openxmlformats-officedocument.wordprocessingml.document        [OFFICE]
+application/vnd.openxmlformats-officedocument.wordprocessingml.template                [OFFICE]
+application/vnd.ms-word.document.macroEnabled.12                               [OFFICE]
+application/vnd.ms-word.template.macroEnabled.12                               [OFFICE]
+application/vnd.openxmlformats-officedocument.presentationml.template          [OFFICE]
+application/vnd.openxmlformats-officedocument.presentationml.slideshow         [OFFICE]
+application/vnd.openxmlformats-officedocument.presentationml.presentation      [OFFICE]
+application/vnd.ms-powerpoint.addin.macroEnabled.12                            [OFFICE]
+application/vnd.ms-powerpoint.presentation.macroEnabled.12                     [OFFICE]
+application/vnd.ms-powerpoint.presentation.macroEnabled.12                     [OFFICE]
+application/vnd.ms-powerpoint.slideshow.macroEnabled.12                                [OFFICE]
+application/vnd.openxmlformats-officedocument.spreadsheetml.sheet              [OFFICE]
+application/vnd.openxmlformats-officedocument.spreadsheetml.template           [OFFICE]
+application/vnd.ms-excel.sheet.macroEnabled.12                                 [OFFICE]
+application/vnd.ms-excel.template.macroEnabled.12                              [OFFICE]
+application/vnd.ms-excel.addin.macroEnabled.12                                 [OFFICE]
+application/vnd.ms-excel.sheet.binary.macroEnabled.12                          [OFFICE]
+application/acad application/x-acad application/autocad_dwg image/x-dwg application/dwg application/x-dwg application/x-autocad image/vnd.dwg drawing/dwg [DRAWING]
+chemical/x-mdl-molfile     [DRAWING]
+chemical/x-mdl-sdfile      [DRAWING]
+chemical/x-mdl-rxnfile     [DRAWING]
+chemical/x-mdl-rdfile      [DRAWING]
+chemical/x-mdl-rgfile      [DRAWING]
diff --git a/includes/libs/mime/mime.types b/includes/libs/mime/mime.types
new file mode 100644 (file)
index 0000000..b4f515a
--- /dev/null
@@ -0,0 +1,188 @@
+application/acad dwg
+application/andrew-inset ez
+application/mac-binhex40 hqx
+application/mac-compactpro cpt
+application/mathml+xml mathml
+application/msword doc dot
+application/octet-stream bin dms lha lzh exe class so dll
+application/oda oda
+application/ogg ogx ogg ogm ogv oga spx opus
+application/pdf pdf
+application/postscript ai eps ps
+application/rdf+xml rdf
+application/smil smi smil
+application/srgs gram
+application/srgs+xml grxml
+application/vnd.mif mif
+application/vnd.ms-excel xls xlt xla
+application/vnd.ms-powerpoint ppt pot pps ppa
+application/vnd.wap.wbxml wbxml
+application/vnd.wap.wmlc wmlc
+application/vnd.wap.wmlscriptc wmlsc
+application/voicexml+xml vxml
+application/x-7z-compressed 7z
+application/x-bcpio bcpio
+application/x-bzip bz
+application/x-bzip2 bz2
+application/x-cdlink vcd
+application/x-chess-pgn pgn
+application/x-cpio cpio
+application/x-csh csh
+application/x-dia-diagram dia
+application/x-director dcr dir dxr
+application/x-dvi dvi
+application/x-futuresplash spl
+application/x-gtar gtar tar
+application/x-gzip gz
+application/x-hdf hdf
+application/x-jar jar
+application/javascript js
+application/json json
+application/x-koan skp skd skt skm
+application/x-latex latex
+application/x-netcdf nc cdf
+application/x-sh sh
+application/x-shar shar
+application/x-shockwave-flash swf
+application/x-stuffit sit
+application/x-sv4cpio sv4cpio
+application/x-sv4crc sv4crc
+application/x-tar tar
+application/x-tcl tcl
+application/x-tex tex
+application/x-texinfo texinfo texi
+application/x-troff t tr roff
+application/x-troff-man man
+application/x-troff-me me
+application/x-troff-ms ms
+application/x-ustar ustar
+application/x-wais-source src
+application/x-xpinstall xpi
+application/xhtml+xml xhtml xht
+application/xslt+xml xslt
+application/xml xml xsl xsd kml
+application/xml-dtd dtd
+application/zip zip jar xpi sxc stc sxd std sxi sti sxm stm sxw stw
+application/x-rar rar
+application/font-woff woff
+application/font-woff2 woff2
+application/vnd.ms-fontobject eot
+application/x-font-ttf ttf
+audio/basic au snd
+audio/midi mid midi kar
+audio/mpeg mpga mp2 mp3
+audio/ogg oga ogg spx opus
+video/webm webm
+audio/webm webm
+audio/x-aiff aif aiff aifc
+audio/x-matroska mka mkv
+audio/x-mpegurl m3u
+audio/x-ogg oga ogg spx opus
+audio/x-pn-realaudio ram rm
+audio/x-pn-realaudio-plugin rpm
+audio/x-realaudio ra
+audio/x-wav wav
+audio/wav wav
+audio/x-flac flac
+audio/flac flac
+chemical/x-pdb pdb
+chemical/x-xyz xyz
+image/bmp bmp
+image/cgm cgm
+image/gif gif
+image/ief ief
+image/jp2 j2k jp2 jpg2
+image/jpeg jpeg jpg jpe
+image/png png apng
+image/svg+xml svg
+image/tiff tiff tif
+image/vnd.djvu djvu djv
+image/vnd.microsoft.icon ico
+image/vnd.wap.wbmp wbmp
+image/webp webp
+image/x-cmu-raster ras
+image/x-icon ico
+image/x-ms-bmp bmp
+image/x-portable-anymap pnm
+image/x-portable-bitmap pbm
+image/x-portable-graymap pgm
+image/x-portable-pixmap ppm
+image/x-rgb rgb
+image/x-photoshop psd
+image/x-xbitmap xbm
+image/x-xpixmap xpm
+image/x-xwindowdump xwd
+model/iges igs iges
+model/mesh msh mesh silo
+model/vrml wrl vrml
+text/calendar ics ifb
+text/css css
+text/csv csv
+text/html html htm
+text/plain txt
+text/richtext rtx
+text/rtf rtf
+text/sgml sgml sgm
+text/tab-separated-values tsv
+text/vnd.wap.wml wml
+text/vnd.wap.wmlscript wmls
+text/xml xml xsl xslt rss rdf
+text/x-component htc
+text/x-setext etx
+text/x-sawfish jl
+video/mpeg mpeg mpg mpe
+video/mp4 mp4 m4a m4p m4b m4r m4v
+audio/mp4 m4a
+video/ogg ogv ogm ogg
+video/quicktime qt mov
+video/vnd.mpegurl mxu
+video/x-flv flv
+video/x-matroska mkv mka
+video/x-msvideo avi
+video/x-ogg ogv ogm ogg
+video/x-sgi-movie movie
+x-conference/x-cooltalk ice
+application/vnd.oasis.opendocument.chart odc
+application/vnd.oasis.opendocument.chart-template otc
+application/vnd.oasis.opendocument.database odb
+application/vnd.oasis.opendocument.formula odf
+application/vnd.oasis.opendocument.formula-template otf
+application/vnd.oasis.opendocument.graphics odg
+application/vnd.oasis.opendocument.graphics-template otg
+application/vnd.oasis.opendocument.image odi
+application/vnd.oasis.opendocument.image-template oti
+application/vnd.oasis.opendocument.presentation odp
+application/vnd.oasis.opendocument.presentation-template otp
+application/vnd.oasis.opendocument.spreadsheet ods
+application/vnd.oasis.opendocument.spreadsheet-template ots
+application/vnd.oasis.opendocument.text odt
+application/vnd.oasis.opendocument.text-master odm
+application/vnd.oasis.opendocument.text-template ott
+application/vnd.oasis.opendocument.text-web oth
+application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
+application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
+application/vnd.ms-word.document.macroEnabled.12 docm
+application/vnd.ms-word.template.macroEnabled.12 dotm
+application/vnd.openxmlformats-officedocument.presentationml.template potx
+application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
+application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
+application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam
+application/vnd.ms-powerpoint.presentation.macroEnabled.12 pptm
+application/vnd.ms-powerpoint.presentation.macroEnabled.12 potm
+application/vnd.ms-powerpoint.slideshow.macroEnabled.12 ppsm
+application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
+application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
+application/vnd.ms-excel.sheet.macroEnabled.12 xlsm
+application/vnd.ms-excel.template.macroEnabled.12 xltm
+application/vnd.ms-excel.addin.macroEnabled.12 xlam
+application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb
+model/vnd.dwfx+xps dwfx
+application/vnd.ms-xpsdocument xps
+application/x-opc+zip docx dotx docm dotm potx ppsx pptx ppam pptm potm ppsm xlsx xltx xlsm xltm xlam xlsb dwfx xps
+chemical/x-mdl-molfile mol
+chemical/x-mdl-sdfile sdf
+chemical/x-mdl-rxnfile rxn
+chemical/x-mdl-rdfile rd
+chemical/x-mdl-rgfile rg
+application/x-amf amf
+application/sla stl
index d3deefb..d0b68bc 100644 (file)
@@ -29,6 +29,7 @@
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
 use Psr\Log\NullLogger;
+use Wikimedia\ScopedCallback;
 use Wikimedia\WaitConditionLoop;
 
 /**
index a5a170b..ba63432 100644 (file)
@@ -25,6 +25,7 @@
  */
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
+use Wikimedia\ScopedCallback;
 
 /**
  * Relational database abstraction object
@@ -78,7 +79,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        /** @var callback Error logging callback */
        protected $errorLogger;
 
-       /** @var resource Database connection */
+       /** @var resource|null Database connection */
        protected $mConn = null;
        /** @var bool */
        protected $mOpened = false;
@@ -382,7 +383,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        }
                        if ( !isset( $p['errorLogger'] ) ) {
                                $p['errorLogger'] = function ( Exception $e ) {
-                                       trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_WARNING );
+                                       trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
                                };
                        }
 
@@ -608,6 +609,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                return !!( $this->mFlags & $flag );
        }
 
+       /**
+        * @param string $name Class field name
+        * @return mixed
+        * @deprecated Since 1.28
+        */
        public function getProperty( $name ) {
                return $this->$name;
        }
@@ -651,14 +657,22 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                if ( $this->htmlErrors !== false ) {
                        ini_set( 'html_errors', $this->htmlErrors );
                }
+
+               return $this->getLastPHPError();
+       }
+
+       /**
+        * @return string|bool Last PHP error for this DB (typically connection errors)
+        */
+       protected function getLastPHPError() {
                if ( $this->mPHPError ) {
                        $error = preg_replace( '!\[<a.*</a>\]!', '', $this->mPHPError );
                        $error = preg_replace( '!^.*?:\s?(.*)$!', '$1', $error );
 
                        return $error;
-               } else {
-                       return false;
                }
+
+               return false;
        }
 
        /**
@@ -773,8 +787,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         * @return bool
         */
        protected function isTransactableQuery( $sql ) {
-               $verb = $this->getQueryVerb( $sql );
-               return !in_array( $verb, [ 'BEGIN', 'COMMIT', 'ROLLBACK', 'SHOW', 'SET' ], true );
+               return !in_array(
+                       $this->getQueryVerb( $sql ),
+                       [ 'BEGIN', 'COMMIT', 'ROLLBACK', 'SHOW', 'SET', 'CREATE', 'ALTER' ],
+                       true
+               );
        }
 
        /**
@@ -2828,7 +2845,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        $fnames = implode( ', ', $this->pendingWriteAndCallbackCallers() );
                        throw new DBUnexpectedError(
                                $this,
-                               "$fname: Cannot COMMIT to clear snapshot because writes are pending ($fnames)."
+                               "$fname: Cannot flush snapshot because writes are pending ($fnames)."
                        );
                }
 
@@ -3249,7 +3266,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        $fnames = implode( ', ', $this->pendingWriteAndCallbackCallers() );
                        throw new DBUnexpectedError(
                                $this,
-                               "$fname: Cannot COMMIT to clear snapshot because writes are pending ($fnames)."
+                               "$fname: Cannot flush pre-lock snapshot because writes are pending ($fnames)."
                        );
                }
 
@@ -3368,6 +3385,28 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                return true;
        }
 
+       /**
+        * Get the underlying binding handle, mConn
+        *
+        * Makes sure that mConn is set (disconnects and ping() failure can unset it).
+        * This catches broken callers than catch and ignore disconnection exceptions.
+        * Unlike checking isOpen(), this is safe to call inside of open().
+        *
+        * @return resource|object
+        * @throws DBUnexpectedError
+        * @since 1.26
+        */
+       protected function getBindingHandle() {
+               if ( !$this->mConn ) {
+                       throw new DBUnexpectedError(
+                               $this,
+                               'DB connection was already closed or the connection dropped.'
+                       );
+               }
+
+               return $this->mConn;
+       }
+
        /**
         * @since 1.19
         * @return string
@@ -3422,8 +3461,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                }
 
                if ( $this->mConn ) {
-                       // Avoid connection leaks for sanity
+                       // Avoid connection leaks for sanity. Normally, resources close at script completion.
+                       // The connection might already be closed in zend/hhvm by now, so suppress warnings.
+                       \MediaWiki\suppressWarnings();
                        $this->closeConnection();
+                       \MediaWiki\restoreWarnings();
                        $this->mConn = false;
                        $this->mOpened = false;
                }
index 9662a5b..3b7681e 100644 (file)
@@ -1204,28 +1204,6 @@ abstract class DatabaseMysqlBase extends Database {
                return $errno == 2013 || $errno == 2006;
        }
 
-       /**
-        * Get the underlying binding handle, mConn
-        *
-        * Makes sure that mConn is set (disconnects and ping() failure can unset it).
-        * This catches broken callers than catch and ignore disconnection exceptions.
-        * Unlike checking isOpen(), this is safe to call inside of open().
-        *
-        * @return resource|object
-        * @throws DBUnexpectedError
-        * @since 1.26
-        */
-       protected function getBindingHandle() {
-               if ( !$this->mConn ) {
-                       throw new DBUnexpectedError(
-                               $this,
-                               'DB connection was already closed or the connection dropped.'
-                       );
-               }
-
-               return $this->mConn;
-       }
-
        /**
         * @param string $oldName
         * @param string $newName
index c34f901..2f27ff9 100644 (file)
@@ -29,8 +29,7 @@
  * @see Database
  */
 class DatabaseMysqli extends DatabaseMysqlBase {
-       /** @var mysqli */
-       protected $mConn;
+       /** @var $mConn mysqli */
 
        /**
         * @param string $sql
index f82d76d..016b9cd 100644 (file)
@@ -61,10 +61,12 @@ class DatabasePostgres extends Database {
        }
 
        function hasConstraint( $name ) {
+               $conn = $this->getBindingHandle();
+
                $sql = "SELECT 1 FROM pg_catalog.pg_constraint c, pg_catalog.pg_namespace n " .
                        "WHERE c.connamespace = n.oid AND conname = '" .
-                       pg_escape_string( $this->mConn, $name ) . "' AND n.nspname = '" .
-                       pg_escape_string( $this->mConn, $this->getCoreSchema() ) . "'";
+                       pg_escape_string( $conn, $name ) . "' AND n.nspname = '" .
+                       pg_escape_string( $conn, $this->getCoreSchema() ) . "'";
                $res = $this->doQuery( $sql );
 
                return $this->numRows( $res );
@@ -90,10 +92,6 @@ class DatabasePostgres extends Database {
                        );
                }
 
-               if ( !strlen( $user ) ) { # e.g. the class is being loaded
-                       return null;
-               }
-
                $this->mServer = $server;
                $this->mUser = $user;
                $this->mPassword = $password;
@@ -119,7 +117,8 @@ class DatabasePostgres extends Database {
                $this->installErrorHandler();
 
                try {
-                       $this->mConn = pg_connect( $this->connectString );
+                       // Use new connections to let LoadBalancer/LBFactory handle reuse
+                       $this->mConn = pg_connect( $this->connectString, PGSQL_CONNECT_FORCE_NEW );
                } catch ( Exception $ex ) {
                        $this->restoreErrorHandler();
                        throw $ex;
@@ -128,10 +127,11 @@ class DatabasePostgres extends Database {
                $phpError = $this->restoreErrorHandler();
 
                if ( !$this->mConn ) {
-                       $this->queryLogger->debug( "DB connection error\n" );
                        $this->queryLogger->debug(
+                               "DB connection error\n" .
                                "Server: $server, Database: $dbName, User: $user, Password: " .
-                               substr( $password, 0, 3 ) . "...\n" );
+                               substr( $password, 0, 3 ) . "...\n"
+                       );
                        $this->queryLogger->debug( $this->lastError() . "\n" );
                        throw new DBConnectionError( $this, str_replace( "\n", ' ', $phpError ) );
                }
@@ -185,19 +185,21 @@ class DatabasePostgres extends Database {
         * @return bool
         */
        protected function closeConnection() {
-               return pg_close( $this->mConn );
+               return $this->mConn ? pg_close( $this->mConn ) : true;
        }
 
        public function doQuery( $sql ) {
+               $conn = $this->getBindingHandle();
+
                $sql = mb_convert_encoding( $sql, 'UTF-8' );
                // Clear previously left over PQresult
-               while ( $res = pg_get_result( $this->mConn ) ) {
+               while ( $res = pg_get_result( $conn ) ) {
                        pg_free_result( $res );
                }
-               if ( pg_send_query( $this->mConn, $sql ) === false ) {
+               if ( pg_send_query( $conn, $sql ) === false ) {
                        throw new DBUnexpectedError( $this, "Unable to post new query to PostgreSQL\n" );
                }
-               $this->mLastResult = pg_get_result( $this->mConn );
+               $this->mLastResult = pg_get_result( $conn );
                $this->mAffectedRows = null;
                if ( pg_result_error( $this->mLastResult ) ) {
                        return false;
@@ -281,10 +283,11 @@ class DatabasePostgres extends Database {
 
                # @todo hashar: not sure if the following test really trigger if the object
                #          fetching failed.
-               if ( pg_last_error( $this->mConn ) ) {
+               $conn = $this->getBindingHandle();
+               if ( pg_last_error( $conn ) ) {
                        throw new DBUnexpectedError(
                                $this,
-                               'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) )
+                               'SQL error: ' . htmlspecialchars( pg_last_error( $conn ) )
                        );
                }
 
@@ -298,10 +301,12 @@ class DatabasePostgres extends Database {
                MediaWiki\suppressWarnings();
                $row = pg_fetch_array( $res );
                MediaWiki\restoreWarnings();
-               if ( pg_last_error( $this->mConn ) ) {
+
+               $conn = $this->getBindingHandle();
+               if ( pg_last_error( $conn ) ) {
                        throw new DBUnexpectedError(
                                $this,
-                               'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) )
+                               'SQL error: ' . htmlspecialchars( pg_last_error( $conn ) )
                        );
                }
 
@@ -315,10 +320,12 @@ class DatabasePostgres extends Database {
                MediaWiki\suppressWarnings();
                $n = pg_num_rows( $res );
                MediaWiki\restoreWarnings();
-               if ( pg_last_error( $this->mConn ) ) {
+
+               $conn = $this->getBindingHandle();
+               if ( pg_last_error( $conn ) ) {
                        throw new DBUnexpectedError(
                                $this,
-                               'SQL error: ' . htmlspecialchars( pg_last_error( $this->mConn ) )
+                               'SQL error: ' . htmlspecialchars( pg_last_error( $conn ) )
                        );
                }
 
@@ -371,9 +378,9 @@ class DatabasePostgres extends Database {
                        } else {
                                return pg_last_error();
                        }
-               } else {
-                       return 'No database connection';
                }
+
+               return $this->getLastPHPError() ?: 'No database connection';
        }
 
        function lastErrno() {
@@ -1033,7 +1040,7 @@ __INDEXATTR__;
                                $this->mCoreSchema . "\"\n" );
                }
                /* Commit SET otherwise it will be rollbacked on error or IGNORE SELECT */
-               $this->commit( __METHOD__ );
+               $this->commit( __METHOD__, self::FLUSHING_INTERNAL );
        }
 
        /**
@@ -1051,7 +1058,8 @@ __INDEXATTR__;
         */
        function getServerVersion() {
                if ( !isset( $this->numericVersion ) ) {
-                       $versionInfo = pg_version( $this->mConn );
+                       $conn = $this->getBindingHandle();
+                       $versionInfo = pg_version( $conn );
                        if ( version_compare( $versionInfo['client'], '7.4.0', 'lt' ) ) {
                                // Old client, abort install
                                $this->numericVersion = '7.3 or earlier';
@@ -1060,7 +1068,7 @@ __INDEXATTR__;
                                $this->numericVersion = $versionInfo['server'];
                        } else {
                                // Bug 16937: broken pgsql extension from PHP<5.3
-                               $this->numericVersion = pg_parameter_status( $this->mConn, 'server_version' );
+                               $this->numericVersion = pg_parameter_status( $conn, 'server_version' );
                        }
                }
 
@@ -1229,7 +1237,7 @@ SQL;
        function strencode( $s ) {
                // Should not be called by us
 
-               return pg_escape_string( $this->mConn, $s );
+               return pg_escape_string( $this->getBindingHandle(), $s );
        }
 
        /**
@@ -1237,6 +1245,8 @@ SQL;
         * @return string|int
         */
        function addQuotes( $s ) {
+               $conn = $this->getBindingHandle();
+
                if ( is_null( $s ) ) {
                        return 'NULL';
                } elseif ( is_bool( $s ) ) {
@@ -1245,12 +1255,12 @@ SQL;
                        if ( $s instanceof PostgresBlob ) {
                                $s = $s->fetch();
                        } else {
-                               $s = pg_escape_bytea( $this->mConn, $s->fetch() );
+                               $s = pg_escape_bytea( $conn, $s->fetch() );
                        }
                        return "'$s'";
                }
 
-               return "'" . pg_escape_string( $this->mConn, $s ) . "'";
+               return "'" . pg_escape_string( $conn, $s ) . "'";
        }
 
        /**
index 3ccf3f0..31bb26b 100644 (file)
@@ -44,8 +44,7 @@ class DatabaseSqlite extends Database {
        /** @var resource */
        protected $mLastResult;
 
-       /** @var PDO */
-       protected $mConn;
+       /** @var $mConn PDO */
 
        /** @var FSLockManager (hopefully on the same server as the DB) */
        protected $lockMgr;
index c32a7ff..c80fdec 100644 (file)
@@ -23,6 +23,7 @@
  * @file
  * @ingroup Database
  */
+use Wikimedia\ScopedCallback;
 
 /**
  * Basic database interface for live and lazy-loaded relation database handles
@@ -321,14 +322,6 @@ interface IDatabase {
         */
        public function getFlag( $flag );
 
-       /**
-        * General read-only accessor
-        *
-        * @param string $name
-        * @return string
-        */
-       public function getProperty( $name );
-
        /**
         * @return string
         */
index 929bd4d..f3a3275 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 use Psr\Log\LoggerInterface;
+use Wikimedia\ScopedCallback;
 
 /**
  * An interface for generating database load balancers
@@ -96,7 +97,7 @@ abstract class LBFactory implements ILBFactory {
                $this->errorLogger = isset( $conf['errorLogger'] )
                        ? $conf['errorLogger']
                        : function ( Exception $e ) {
-                               trigger_error( E_WARNING, get_class( $e ) . ': ' . $e->getMessage() );
+                               trigger_error( E_USER_WARNING, get_class( $e ) . ': ' . $e->getMessage() );
                        };
 
                $this->profiler = isset( $params['profiler'] ) ? $params['profiler'] : null;
index 32df19d..a86e1de 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup Database
  */
 use Psr\Log\LoggerInterface;
+use Wikimedia\ScopedCallback;
 
 /**
  * Database connection, tracking, load balancing, and transaction manager for a cluster
@@ -189,7 +190,7 @@ class LoadBalancer implements ILoadBalancer {
                $this->errorLogger = isset( $params['errorLogger'] )
                        ? $params['errorLogger']
                        : function ( Exception $e ) {
-                               trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_WARNING );
+                               trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
                        };
 
                foreach ( [ 'replLogger', 'connLogger', 'queryLogger', 'perfLogger' ] as $key ) {
@@ -552,7 +553,7 @@ class LoadBalancer implements ILoadBalancer {
                if ( $i == self::DB_REPLICA ) {
                        $this->mLastError = 'Unknown error'; // reset error string
                        # Try the general server pool if $groups are unavailable.
-                       $i = in_array( false, $groups, true )
+                       $i = ( $groups === [ false ] )
                                ? false // don't bother with this if that is what was tried above
                                : $this->getReaderIndex( false, $domain );
                        # Couldn't find a working server in getReaderIndex()?
@@ -886,7 +887,7 @@ class LoadBalancer implements ILoadBalancer {
                        // If all servers were busy, mLastError will contain something sensible
                        throw new DBConnectionError( null, $this->mLastError );
                } else {
-                       $context['db_server'] = $conn->getProperty( 'mServer' );
+                       $context['db_server'] = $conn->getServer();
                        $this->connLogger->warning(
                                "Connection error: {last_error} ({db_server})",
                                $context
index 9de4850..0dec95f 100644 (file)
@@ -75,7 +75,7 @@ class LoadBalancerSingle extends LoadBalancer {
         *
         * @return IDatabase
         */
-       protected function reallyOpenConnection( $server, $dbNameOverride = false ) {
+       protected function reallyOpenConnection( array $server, $dbNameOverride = false ) {
                return $this->db;
        }
 }
index 99c9126..da4909d 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 use Psr\Log\LoggerInterface;
+use Wikimedia\ScopedCallback;
 
 /**
  * Basic DB load monitor with no external dependencies
index 70f67b7..29bbf40 100644 (file)
@@ -24,6 +24,7 @@
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
 use Psr\Log\NullLogger;
+use Wikimedia\ScopedCallback;
 
 /**
  * Class for reading xmp data containing properties relevant to
index 8360920..f3b33ac 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  * @ingroup Media
  */
+use Wikimedia\ScopedCallback;
 
 /**
  * Handler for SVG images.
diff --git a/includes/mime.info b/includes/mime.info
deleted file mode 100644 (file)
index b04d3c6..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-# MIME type info file.
-# the first MIME type in each line is the "main" MIME type,
-# the others are aliases for this type
-# the media type is given in upper case and square brackets,
-# like [BITMAP], and must indicate a media type as defined by
-# the MEDIATYPE_xxx constants in Defines.php
-
-
-image/gif      [BITMAP]
-image/png image/x-png  [BITMAP]
-image/ief      [BITMAP]
-image/jpeg image/pjpeg [BITMAP]
-image/jp2      [BITMAP]
-image/xbm      [BITMAP]
-image/tiff     [BITMAP]
-image/x-icon image/x-ico image/vnd.microsoft.icon      [BITMAP]
-image/x-rgb    [BITMAP]
-image/x-portable-pixmap                [BITMAP]
-image/x-portable-graymap image/x-portable-greymap      [BITMAP]
-image/x-bmp image/x-ms-bmp image/bmp application/x-bmp application/bmp [BITMAP]
-image/x-photoshop image/psd image/x-psd image/photoshop image/vnd.adobe.photoshop      [BITMAP]
-image/vnd.djvu image/x.djvu image/x-djvu [BITMAP]
-image/webp     [BITMAP]
-
-image/svg+xml application/svg+xml application/svg image/svg    [DRAWING]
-application/postscript [DRAWING]
-application/x-latex    [DRAWING]
-application/x-tex      [DRAWING]
-application/x-dia-diagram [DRAWING]
-
-
-audio/mpeg audio/mp3 audio/mpeg3       [AUDIO]
-audio/mp4                              [AUDIO]
-audio/wav audio/x-wav audio/wave       [AUDIO]
-audio/midi audio/mid   [AUDIO]
-audio/basic            [AUDIO]
-audio/ogg              [AUDIO]
-audio/x-aiff           [AUDIO]
-audio/x-pn-realaudio   [AUDIO]
-audio/x-realaudio      [AUDIO]
-audio/webm             [AUDIO]
-audio/x-matroska       [AUDIO]
-audio/x-flac           [AUDIO]
-audio/flac             [AUDIO]
-
-video/mpeg application/mpeg    [VIDEO]
-video/ogg                      [VIDEO]
-video/x-sgi-video              [VIDEO]
-video/x-flv                    [VIDEO]
-video/webm                     [VIDEO]
-video/x-matroska               [VIDEO]
-video/mp4                      [VIDEO]
-
-application/ogg application/x-ogg audio/ogg audio/x-ogg video/ogg video/x-ogg          [MULTIMEDIA]
-
-application/x-shockwave-flash  [MULTIMEDIA]
-audio/x-pn-realaudio-plugin    [MULTIMEDIA]
-model/iges     [MULTIMEDIA]
-model/mesh     [MULTIMEDIA]
-model/vrml     [MULTIMEDIA]
-video/quicktime        [MULTIMEDIA]
-video/x-msvideo        [MULTIMEDIA]
-
-text/plain     [TEXT]
-text/html application/xhtml+xml        [TEXT]
-application/xml text/xml       [TEXT]
-text   [TEXT]
-application/json       [TEXT]
-text/csv       [TEXT]
-text/tab-separated-values      [TEXT]
-
-application/zip application/x-zip      [ARCHIVE]
-application/x-gzip     [ARCHIVE]
-application/x-bzip     [ARCHIVE]
-application/x-bzip2    [ARCHIVE]
-application/x-tar      [ARCHIVE]
-application/x-stuffit  [ARCHIVE]
-application/x-opc+zip  [ARCHIVE]
-application/x-7z-compressed [ARCHIVE]
-
-application/javascript text/javascript application/x-javascript application/x-ecmascript text/ecmascript       [EXECUTABLE]
-application/x-bash     [EXECUTABLE]
-application/x-sh       [EXECUTABLE]
-application/x-csh      [EXECUTABLE]
-application/x-tcsh     [EXECUTABLE]
-application/x-tcl      [EXECUTABLE]
-application/x-perl     [EXECUTABLE]
-application/x-python   [EXECUTABLE]
-
-application/pdf application/acrobat    [OFFICE]
-application/msword             [OFFICE]
-application/vnd.ms-excel       [OFFICE]
-application/vnd.ms-powerpoint  [OFFICE]
-application/x-director         [OFFICE]
-text/rtf                       [OFFICE]
-
-application/vnd.openxmlformats-officedocument.wordprocessingml.document        [OFFICE]
-application/vnd.openxmlformats-officedocument.wordprocessingml.template                [OFFICE]
-application/vnd.ms-word.document.macroEnabled.12                               [OFFICE]
-application/vnd.ms-word.template.macroEnabled.12                               [OFFICE]
-application/vnd.openxmlformats-officedocument.presentationml.template          [OFFICE]
-application/vnd.openxmlformats-officedocument.presentationml.slideshow         [OFFICE]
-application/vnd.openxmlformats-officedocument.presentationml.presentation      [OFFICE]
-application/vnd.ms-powerpoint.addin.macroEnabled.12                            [OFFICE]
-application/vnd.ms-powerpoint.presentation.macroEnabled.12                     [OFFICE]
-application/vnd.ms-powerpoint.presentation.macroEnabled.12                     [OFFICE]
-application/vnd.ms-powerpoint.slideshow.macroEnabled.12                                [OFFICE]
-application/vnd.openxmlformats-officedocument.spreadsheetml.sheet              [OFFICE]
-application/vnd.openxmlformats-officedocument.spreadsheetml.template           [OFFICE]
-application/vnd.ms-excel.sheet.macroEnabled.12                                 [OFFICE]
-application/vnd.ms-excel.template.macroEnabled.12                              [OFFICE]
-application/vnd.ms-excel.addin.macroEnabled.12                                 [OFFICE]
-application/vnd.ms-excel.sheet.binary.macroEnabled.12                          [OFFICE]
-application/acad application/x-acad application/autocad_dwg image/x-dwg application/dwg application/x-dwg application/x-autocad image/vnd.dwg drawing/dwg [DRAWING]
-chemical/x-mdl-molfile     [DRAWING]
-chemical/x-mdl-sdfile      [DRAWING]
-chemical/x-mdl-rxnfile     [DRAWING]
-chemical/x-mdl-rdfile      [DRAWING]
-chemical/x-mdl-rgfile      [DRAWING]
diff --git a/includes/mime.types b/includes/mime.types
deleted file mode 100644 (file)
index b4f515a..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-application/acad dwg
-application/andrew-inset ez
-application/mac-binhex40 hqx
-application/mac-compactpro cpt
-application/mathml+xml mathml
-application/msword doc dot
-application/octet-stream bin dms lha lzh exe class so dll
-application/oda oda
-application/ogg ogx ogg ogm ogv oga spx opus
-application/pdf pdf
-application/postscript ai eps ps
-application/rdf+xml rdf
-application/smil smi smil
-application/srgs gram
-application/srgs+xml grxml
-application/vnd.mif mif
-application/vnd.ms-excel xls xlt xla
-application/vnd.ms-powerpoint ppt pot pps ppa
-application/vnd.wap.wbxml wbxml
-application/vnd.wap.wmlc wmlc
-application/vnd.wap.wmlscriptc wmlsc
-application/voicexml+xml vxml
-application/x-7z-compressed 7z
-application/x-bcpio bcpio
-application/x-bzip bz
-application/x-bzip2 bz2
-application/x-cdlink vcd
-application/x-chess-pgn pgn
-application/x-cpio cpio
-application/x-csh csh
-application/x-dia-diagram dia
-application/x-director dcr dir dxr
-application/x-dvi dvi
-application/x-futuresplash spl
-application/x-gtar gtar tar
-application/x-gzip gz
-application/x-hdf hdf
-application/x-jar jar
-application/javascript js
-application/json json
-application/x-koan skp skd skt skm
-application/x-latex latex
-application/x-netcdf nc cdf
-application/x-sh sh
-application/x-shar shar
-application/x-shockwave-flash swf
-application/x-stuffit sit
-application/x-sv4cpio sv4cpio
-application/x-sv4crc sv4crc
-application/x-tar tar
-application/x-tcl tcl
-application/x-tex tex
-application/x-texinfo texinfo texi
-application/x-troff t tr roff
-application/x-troff-man man
-application/x-troff-me me
-application/x-troff-ms ms
-application/x-ustar ustar
-application/x-wais-source src
-application/x-xpinstall xpi
-application/xhtml+xml xhtml xht
-application/xslt+xml xslt
-application/xml xml xsl xsd kml
-application/xml-dtd dtd
-application/zip zip jar xpi sxc stc sxd std sxi sti sxm stm sxw stw
-application/x-rar rar
-application/font-woff woff
-application/font-woff2 woff2
-application/vnd.ms-fontobject eot
-application/x-font-ttf ttf
-audio/basic au snd
-audio/midi mid midi kar
-audio/mpeg mpga mp2 mp3
-audio/ogg oga ogg spx opus
-video/webm webm
-audio/webm webm
-audio/x-aiff aif aiff aifc
-audio/x-matroska mka mkv
-audio/x-mpegurl m3u
-audio/x-ogg oga ogg spx opus
-audio/x-pn-realaudio ram rm
-audio/x-pn-realaudio-plugin rpm
-audio/x-realaudio ra
-audio/x-wav wav
-audio/wav wav
-audio/x-flac flac
-audio/flac flac
-chemical/x-pdb pdb
-chemical/x-xyz xyz
-image/bmp bmp
-image/cgm cgm
-image/gif gif
-image/ief ief
-image/jp2 j2k jp2 jpg2
-image/jpeg jpeg jpg jpe
-image/png png apng
-image/svg+xml svg
-image/tiff tiff tif
-image/vnd.djvu djvu djv
-image/vnd.microsoft.icon ico
-image/vnd.wap.wbmp wbmp
-image/webp webp
-image/x-cmu-raster ras
-image/x-icon ico
-image/x-ms-bmp bmp
-image/x-portable-anymap pnm
-image/x-portable-bitmap pbm
-image/x-portable-graymap pgm
-image/x-portable-pixmap ppm
-image/x-rgb rgb
-image/x-photoshop psd
-image/x-xbitmap xbm
-image/x-xpixmap xpm
-image/x-xwindowdump xwd
-model/iges igs iges
-model/mesh msh mesh silo
-model/vrml wrl vrml
-text/calendar ics ifb
-text/css css
-text/csv csv
-text/html html htm
-text/plain txt
-text/richtext rtx
-text/rtf rtf
-text/sgml sgml sgm
-text/tab-separated-values tsv
-text/vnd.wap.wml wml
-text/vnd.wap.wmlscript wmls
-text/xml xml xsl xslt rss rdf
-text/x-component htc
-text/x-setext etx
-text/x-sawfish jl
-video/mpeg mpeg mpg mpe
-video/mp4 mp4 m4a m4p m4b m4r m4v
-audio/mp4 m4a
-video/ogg ogv ogm ogg
-video/quicktime qt mov
-video/vnd.mpegurl mxu
-video/x-flv flv
-video/x-matroska mkv mka
-video/x-msvideo avi
-video/x-ogg ogv ogm ogg
-video/x-sgi-movie movie
-x-conference/x-cooltalk ice
-application/vnd.oasis.opendocument.chart odc
-application/vnd.oasis.opendocument.chart-template otc
-application/vnd.oasis.opendocument.database odb
-application/vnd.oasis.opendocument.formula odf
-application/vnd.oasis.opendocument.formula-template otf
-application/vnd.oasis.opendocument.graphics odg
-application/vnd.oasis.opendocument.graphics-template otg
-application/vnd.oasis.opendocument.image odi
-application/vnd.oasis.opendocument.image-template oti
-application/vnd.oasis.opendocument.presentation odp
-application/vnd.oasis.opendocument.presentation-template otp
-application/vnd.oasis.opendocument.spreadsheet ods
-application/vnd.oasis.opendocument.spreadsheet-template ots
-application/vnd.oasis.opendocument.text odt
-application/vnd.oasis.opendocument.text-master odm
-application/vnd.oasis.opendocument.text-template ott
-application/vnd.oasis.opendocument.text-web oth
-application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
-application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
-application/vnd.ms-word.document.macroEnabled.12 docm
-application/vnd.ms-word.template.macroEnabled.12 dotm
-application/vnd.openxmlformats-officedocument.presentationml.template potx
-application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
-application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
-application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam
-application/vnd.ms-powerpoint.presentation.macroEnabled.12 pptm
-application/vnd.ms-powerpoint.presentation.macroEnabled.12 potm
-application/vnd.ms-powerpoint.slideshow.macroEnabled.12 ppsm
-application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
-application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
-application/vnd.ms-excel.sheet.macroEnabled.12 xlsm
-application/vnd.ms-excel.template.macroEnabled.12 xltm
-application/vnd.ms-excel.addin.macroEnabled.12 xlam
-application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb
-model/vnd.dwfx+xps dwfx
-application/vnd.ms-xpsdocument xps
-application/x-opc+zip docx dotx docm dotm potx ppsx pptx ppam pptm potm ppsm xlsx xltx xlsm xltm xlam xlsb dwfx xps
-chemical/x-mdl-molfile mol
-chemical/x-mdl-sdfile sdf
-chemical/x-mdl-rxnfile rxn
-chemical/x-mdl-rdfile rd
-chemical/x-mdl-rgfile rg
-application/x-amf amf
-application/sla stl
index f0898ba..2c15235 100644 (file)
@@ -22,6 +22,7 @@
  */
 use MediaWiki\Linker\LinkRenderer;
 use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
 
 /**
  * @defgroup Parser Parser
@@ -1445,6 +1446,7 @@ class Parser {
                                $keyword = 'RFC';
                                $urlmsg = 'rfcurl';
                                $cssClass = 'mw-magiclink-rfc';
+                               $trackingCategory = 'magiclinks-rfc-category';
                                $id = $m[5];
                        } elseif ( substr( $m[0], 0, 4 ) === 'PMID' ) {
                                if ( !$this->mOptions->getMagicPMIDLinks() ) {
@@ -1453,12 +1455,14 @@ class Parser {
                                $keyword = 'PMID';
                                $urlmsg = 'pubmedurl';
                                $cssClass = 'mw-magiclink-pmid';
+                               $trackingCategory = 'magiclinks-pmid-category';
                                $id = $m[5];
                        } else {
                                throw new MWException( __METHOD__ . ': unrecognised match type "' .
                                        substr( $m[0], 0, 20 ) . '"' );
                        }
                        $url = wfMessage( $urlmsg, $id )->inContentLanguage()->text();
+                       $this->addTrackingCategory( $trackingCategory );
                        return Linker::makeExternalLink( $url, "{$keyword} {$id}", true, $cssClass, [], $this->mTitle );
                } elseif ( isset( $m[6] ) && $m[6] !== ''
                        && $this->mOptions->getMagicISBNLinks()
@@ -1472,6 +1476,7 @@ class Parser {
                                ' ' => '',
                                'x' => 'X',
                        ] );
+                       $this->addTrackingCategory( 'magiclinks-isbn-category' );
                        return $this->getLinkRenderer()->makeKnownLink(
                                SpecialPage::getTitleFor( 'Booksources', $num ),
                                "ISBN $isbn",
index 25c2aa4..9a10878 100644 (file)
@@ -20,6 +20,7 @@
  * @file
  * @ingroup Parser
  */
+use Wikimedia\ScopedCallback;
 
 /**
  * @brief Set options of the Parser
index db9c95b..8b4f01a 100644 (file)
@@ -21,6 +21,7 @@
  * @ingroup Profiler
  * @defgroup Profiler Profiler
  */
+use Wikimedia\ScopedCallback;
 
 /**
  * Profiler base class that defines the interface and some trivial
index 745c233..d613b2e 100644 (file)
@@ -397,7 +397,7 @@ class ExtensionProcessor implements Processor {
                if ( isset( $info['config'] ) ) {
                        foreach ( $info['config'] as $key => $data ) {
                                $value = $data['value'];
-                               if ( isset( $value['merge_strategy'] ) ) {
+                               if ( isset( $data['merge_strategy'] ) ) {
                                        $value[ExtensionRegistry::MERGE_STRATEGY] = $data['merge_strategy'];
                                }
                                if ( isset( $data['path'] ) && $data['path'] ) {
index 35044e1..78ec148 100644 (file)
@@ -84,9 +84,8 @@ class ExtensionRegistry {
        }
 
        public function __construct() {
-               // We use a try/catch instead of the $fallback parameter because
-               // we don't want to fail here if $wgObjectCaches is not configured
-               // properly for APC setup
+               // We use a try/catch because we don't want to fail here
+               // if $wgObjectCaches is not configured properly for APC setup
                try {
                        $this->cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
                } catch ( MWException $e ) {
index 3e94460..796c575 100644 (file)
@@ -25,6 +25,7 @@
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
 use Psr\Log\NullLogger;
+use Wikimedia\ScopedCallback;
 
 /**
  * Abstraction for ResourceLoader modules, with name registration and maxage functionality.
index 31761c3..12f16b6 100644 (file)
@@ -600,7 +600,7 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
         *
         * Calls to save() or clear() will not be delayed.
         *
-        * @return \ScopedCallback When this goes out of scope, a save will be triggered
+        * @return \Wikimedia\ScopedCallback When this goes out of scope, a save will be triggered
         */
        public function delaySave() {
                return $this->backend->delaySave();
index ea811b6..8633715 100644 (file)
@@ -586,11 +586,11 @@ final class SessionBackend {
         *
         * Calls to save() will not be delayed.
         *
-        * @return \ScopedCallback When this goes out of scope, a save will be triggered
+        * @return \Wikimedia\ScopedCallback When this goes out of scope, a save will be triggered
         */
        public function delaySave() {
                $this->delaySave++;
-               return new \ScopedCallback( function () {
+               return new \Wikimedia\ScopedCallback( function () {
                        if ( --$this->delaySave <= 0 ) {
                                $this->delaySave = 0;
                                $this->save();
@@ -751,7 +751,7 @@ final class SessionBackend {
        private function checkPHPSession() {
                if ( !$this->checkPHPSessionRecursionGuard ) {
                        $this->checkPHPSessionRecursionGuard = true;
-                       $reset = new \ScopedCallback( function () {
+                       $reset = new \Wikimedia\ScopedCallback( function () {
                                $this->checkPHPSessionRecursionGuard = false;
                        } );
 
index 87fdcd3..b8e480f 100644 (file)
@@ -880,7 +880,7 @@ final class SessionManager implements SessionManagerInterface {
                        $session->resetId();
                }
 
-               \ScopedCallback::consume( $delay );
+               \Wikimedia\ScopedCallback::consume( $delay );
                return $session;
        }
 
index 11faa28..72e0b88 100644 (file)
  * @ingroup SpecialPage
  */
 class SpecialBookSources extends SpecialPage {
-       /**
-        * ISBN passed to the page, if any
-        */
-       protected $isbn = '';
-
        public function __construct() {
                parent::__construct( 'Booksources' );
        }
@@ -49,19 +44,21 @@ class SpecialBookSources extends SpecialPage {
                $this->setHeaders();
                $this->outputHeader();
 
-               $this->isbn = self::cleanIsbn( $isbn ?: $this->getRequest()->getText( 'isbn' ) );
+               // User provided ISBN
+               $isbn = $isbn ?: $this->getRequest()->getText( 'isbn' );
+               $isbn = trim( $isbn );
 
-               $this->buildForm();
+               $this->buildForm( $isbn );
 
-               if ( $this->isbn !== '' ) {
-                       if ( !self::isValidISBN( $this->isbn ) ) {
+               if ( $isbn !== '' ) {
+                       if ( !self::isValidISBN( $isbn ) ) {
                                $out->wrapWikiMsg(
                                        "<div class=\"error\">\n$1\n</div>",
                                        'booksources-invalid-isbn'
                                );
                        }
 
-                       $this->showList();
+                       $this->showList( $isbn );
                }
        }
 
@@ -121,20 +118,24 @@ class SpecialBookSources extends SpecialPage {
 
        /**
         * Generate a form to allow users to enter an ISBN
+        *
+        * @param string $isbn
         */
-       private function buildForm() {
+       private function buildForm( $isbn ) {
                $formDescriptor = [
                        'isbn' => [
                                'type' => 'text',
                                'name' => 'isbn',
                                'label-message' => 'booksources-isbn',
-                               'default' => $this->isbn,
+                               'default' => $isbn,
                                'autofocus' => true,
                                'required' => true,
                        ],
                ];
 
-               $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+               $context = new DerivativeContext( $this->getContext() );
+               $context->setTitle( $this->getPageTitle() );
+               HTMLForm::factory( 'ooui', $formDescriptor, $context )
                        ->setWrapperLegendMsg( 'booksources-search-legend' )
                        ->setSubmitTextMsg( 'booksources-search' )
                        ->setMethod( 'get' )
@@ -146,17 +147,19 @@ class SpecialBookSources extends SpecialPage {
         * Determine where to get the list of book sources from,
         * format and output them
         *
+        * @param string $isbn
         * @throws MWException
         * @return bool
         */
-       private function showList() {
+       private function showList( $isbn ) {
                $out = $this->getOutput();
 
                global $wgContLang;
 
+               $isbn = self::cleanIsbn( $isbn );
                # Hook to allow extensions to insert additional HTML,
                # e.g. for API-interacting plugins and so on
-               Hooks::run( 'BookInformation', [ $this->isbn, $out ] );
+               Hooks::run( 'BookInformation', [ $isbn, $out ] );
 
                # Check for a local page such as Project:Book_sources and use that if available
                $page = $this->msg( 'booksources' )->inContentLanguage()->text();
@@ -169,7 +172,7 @@ class SpecialBookSources extends SpecialPage {
                                // XXX: in the future, this could be stored as structured data, defining a list of book sources
 
                                $text = $content->getNativeData();
-                               $out->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $text ) );
+                               $out->addWikiText( str_replace( 'MAGICNUMBER', $isbn, $text ) );
 
                                return true;
                        } else {
@@ -182,7 +185,7 @@ class SpecialBookSources extends SpecialPage {
                $out->addHTML( '<ul>' );
                $items = $wgContLang->getBookstoreList();
                foreach ( $items as $label => $url ) {
-                       $out->addHTML( $this->makeListItem( $label, $url ) );
+                       $out->addHTML( $this->makeListItem( $isbn, $label, $url ) );
                }
                $out->addHTML( '</ul>' );
 
@@ -192,12 +195,13 @@ class SpecialBookSources extends SpecialPage {
        /**
         * Format a book source list item
         *
+        * @param string $isbn
         * @param string $label Book source label
         * @param string $url Book source URL
         * @return string
         */
-       private function makeListItem( $label, $url ) {
-               $url = str_replace( '$1', $this->isbn, $url );
+       private function makeListItem( $isbn, $label, $url ) {
+               $url = str_replace( '$1', $isbn, $url );
 
                return Html::rawElement( 'li', [],
                        Html::element( 'a', [ 'href' => $url, 'class' => 'external' ], $label )
index 7b7661d..298d6c4 100644 (file)
@@ -783,32 +783,57 @@ class MovePageForm extends UnlistedSpecialPage {
                LogEventsList::showLogExtract( $out, 'move', $title );
        }
 
+       /**
+        * Show subpages of the page being moved. Section is not shown if both current
+        * namespace does not support subpages and no talk subpages were found.
+        *
+        * @param Title $title Page being moved.
+        */
        function showSubpages( $title ) {
-               if ( !MWNamespace::hasSubpages( $title->getNamespace() ) ) {
+               $nsHasSubpages = MWNamespace::hasSubpages( $title->getNamespace() );
+               $subpages = $title->getSubpages();
+               $count = $subpages instanceof TitleArray ? $subpages->count() : 0;
+
+               $titleIsTalk = $title->isTalkPage();
+               $subpagesTalk = $title->getTalkPage()->getSubpages();
+               $countTalk = $subpagesTalk instanceof TitleArray ? $subpagesTalk->count() : 0;
+               $totalCount = $count + $countTalk;
+
+               if ( !$nsHasSubpages && $countTalk == 0 ) {
                        return;
                }
 
-               $subpages = $title->getSubpages();
-               $count = $subpages instanceof TitleArray ? $subpages->count() : 0;
+               $this->getOutput()->wrapWikiMsg(
+                       '== $1 ==',
+                       [ 'movesubpage', ( $titleIsTalk ? $count : $totalCount ) ]
+               );
+
+               if ( $nsHasSubpages ) {
+                       $this->showSubpagesList( $subpages, $count, 'movesubpagetext', true );
+               }
 
+               if ( !$titleIsTalk && $countTalk > 0 ) {
+                       $this->showSubpagesList( $subpagesTalk, $countTalk, 'movesubpagetalktext' );
+               }
+       }
+
+       function showSubpagesList( $subpages, $pagecount, $wikiMsg, $noSubpageMsg = false ) {
                $out = $this->getOutput();
-               $out->wrapWikiMsg( '== $1 ==', [ 'movesubpage', $count ] );
 
                # No subpages.
-               if ( $count == 0 ) {
+               if ( $pagecount == 0 && $noSubpageMsg ) {
                        $out->addWikiMsg( 'movenosubpage' );
-
                        return;
                }
 
-               $out->addWikiMsg( 'movesubpagetext', $this->getLanguage()->formatNum( $count ) );
+               $out->addWikiMsg( $wikiMsg, $this->getLanguage()->formatNum( $pagecount ) );
                $out->addHTML( "<ul>\n" );
 
                $linkBatch = new LinkBatch( $subpages );
                $linkBatch->setCaller( __METHOD__ );
                $linkBatch->execute();
-
                $linkRenderer = $this->getLinkRenderer();
+
                foreach ( $subpages as $subpage ) {
                        $link = $linkRenderer->makeLink( $subpage );
                        $out->addHTML( "<li>$link</li>\n" );
index 00fc9be..92a65f0 100644 (file)
@@ -26,6 +26,7 @@ use MediaWiki\Session\Token;
 use MediaWiki\Auth\AuthManager;
 use MediaWiki\Auth\AuthenticationResponse;
 use MediaWiki\Auth\AuthenticationRequest;
+use Wikimedia\ScopedCallback;
 
 /**
  * String Some punctuation to prevent editing from broken text-mangling proxies.
@@ -320,7 +321,7 @@ class User implements IDBAccessObject {
         * @return string
         */
        public function __toString() {
-               return $this->getName();
+               return (string)$this->getName();
        }
 
        /**
index 9fc2431..ef2c14a 100644 (file)
@@ -77,16 +77,21 @@ class BatchRowIterator implements RecursiveIterator {
         */
        private $key;
 
+       /**
+        * @var array Additional query options
+        */
+       protected $options = [];
+
        /**
         * @param IDatabase $db The database to read from
         * @param string|array $table      The name or names of the table to read from
         * @param string|array $primaryKey The name or names of the primary key columns
         * @param integer      $batchSize  The number of rows to fetch per iteration
-        * @throws MWException
+        * @throws InvalidArgumentException
         */
        public function __construct( IDatabase $db, $table, $primaryKey, $batchSize ) {
                if ( $batchSize < 1 ) {
-                       throw new MWException( 'Batch size must be at least 1 row.' );
+                       throw new InvalidArgumentException( 'Batch size must be at least 1 row.' );
                }
                $this->db = $db;
                $this->table = $table;
@@ -97,7 +102,7 @@ class BatchRowIterator implements RecursiveIterator {
        }
 
        /**
-        * @param array $condition Query conditions suitable for use with
+        * @param array $conditions Query conditions suitable for use with
         *  IDatabase::select
         */
        public function addConditions( array $conditions ) {
@@ -105,7 +110,15 @@ class BatchRowIterator implements RecursiveIterator {
        }
 
        /**
-        * @param array $condition Query join conditions suitable for use
+        * @param array $options Query options suitable for use with
+        *  IDatabase::select
+        */
+       public function addOptions( array $options ) {
+               $this->options = array_merge( $this->options, $options );
+       }
+
+       /**
+        * @param array $conditions Query join conditions suitable for use
         *  with IDatabase::select
         */
        public function addJoinConditions( array $conditions ) {
@@ -199,7 +212,7 @@ class BatchRowIterator implements RecursiveIterator {
                        [
                                'LIMIT' => $this->batchSize,
                                'ORDER BY' => $this->orderBy,
-                       ],
+                       ] + $this->options,
                        $this->joinConditions
                );
 
index 1e7eda8..39b65c3 100644 (file)
@@ -112,15 +112,8 @@ class BatchRowUpdate {
         *
         * @param callable $output A callback taking a single string
         *  parameter to output
-        *
-        * @throws MWException
         */
-       public function setOutput( $output ) {
-               if ( !is_callable( $output ) ) {
-                       throw new MWException(
-                               'Provided $output param is required to be callable.'
-                       );
-               }
+       public function setOutput( callable $output ) {
                $this->output = $output;
        }
 
index 2756861..3bddd77 100644 (file)
  * @author Chris Steipp
  * @file
  */
+
 use MediaWiki\MediaWikiServices;
 
 class MWCryptHKDF {
 
-       /**
-        * Singleton instance for public use
-        */
-       protected static $singleton = null;
-
-       /**
-        * The persistant cache
-        */
-       protected $cache = null;
-
-       /**
-        * Cache key we'll use for our salt
-        */
-       protected $cacheKey = null;
-
-       /**
-        * The hash algorithm being used
-        */
-       protected $algorithm = null;
-
-       /**
-        * binary string, the salt for the HKDF
-        */
-       protected $salt;
-
-       /**
-        * The pseudorandom key
-        */
-       private $prk;
-
-       /**
-        * The secret key material. This must be kept secret to preserve
-        * the security properties of this RNG.
-        */
-       private $skm;
-
-       /**
-        * The last block (K(i)) of the most recent expanded key
-        */
-       protected $lastK;
-
-       /**
-        * a "context information" string CTXinfo (which may be null)
-        * See http://eprint.iacr.org/2010/264.pdf Section 4.1
-        */
-       protected $context = [];
-
-       /**
-        * Round count is computed based on the hash'es output length,
-        * which neither php nor openssl seem to provide easily.
-        */
-       public static $hashLength = [
-               'md5' => 16,
-               'sha1' => 20,
-               'sha224' => 28,
-               'sha256' => 32,
-               'sha384' => 48,
-               'sha512' => 64,
-               'ripemd128' => 16,
-               'ripemd160' => 20,
-               'ripemd256' => 32,
-               'ripemd320' => 40,
-               'whirlpool' => 64,
-       ];
-
-       /**
-        * @param string $secretKeyMaterial
-        * @param string $algorithm Name of hashing algorithm
-        * @param BagOStuff $cache
-        * @param string|array $context Context to mix into HKDF context
-        * @throws MWException
-        */
-       public function __construct( $secretKeyMaterial, $algorithm, $cache, $context ) {
-               if ( strlen( $secretKeyMaterial ) < 16 ) {
-                       throw new MWException( "MWCryptHKDF secret was too short." );
-               }
-               $this->skm = $secretKeyMaterial;
-               $this->algorithm = $algorithm;
-               $this->cache = $cache;
-               $this->salt = ''; // Initialize a blank salt, see getSaltUsingCache()
-               $this->prk = '';
-               $this->context = is_array( $context ) ? $context : [ $context ];
-
-               // To prevent every call from hitting the same memcache server, pick
-               // from a set of keys to use. mt_rand is only use to pick a random
-               // server, and does not affect the security of the process.
-               $this->cacheKey = wfMemcKey( 'HKDF', mt_rand( 0, 16 ) );
-       }
-
-       /**
-        * Save the last block generated, so the next user will compute a different PRK
-        * from the same SKM. This should keep things unpredictable even if an attacker
-        * is able to influence CTXinfo.
-        */
-       function __destruct() {
-               if ( $this->lastK ) {
-                       $this->cache->set( $this->cacheKey, $this->lastK );
-               }
-       }
-
-       /**
-        * MW specific salt, cached from last run
-        * @return string Binary string
-        */
-       protected function getSaltUsingCache() {
-               if ( $this->salt == '' ) {
-                       $lastSalt = $this->cache->get( $this->cacheKey );
-                       if ( $lastSalt === false ) {
-                               // If we don't have a previous value to use as our salt, we use
-                               // 16 bytes from MWCryptRand, which will use a small amount of
-                               // entropy from our pool. Note, "XTR may be deterministic or keyed
-                               // via an optional “salt value”  (i.e., a non-secret random
-                               // value)..." - http://eprint.iacr.org/2010/264.pdf. However, we
-                               // use a strongly random value since we can.
-                               $lastSalt = MWCryptRand::generate( 16 );
-                       }
-                       // Get a binary string that is hashLen long
-                       $this->salt = hash( $this->algorithm, $lastSalt, true );
-               }
-               return $this->salt;
-       }
-
        /**
         * Return a singleton instance, based on the global configs.
-        * @return self
-        * @throws MWException
+        * @return CryptHKDF
         */
        protected static function singleton() {
-               global $wgHKDFAlgorithm, $wgHKDFSecret, $wgSecretKey;
-
-               $secret = $wgHKDFSecret ?: $wgSecretKey;
-               if ( !$secret ) {
-                       throw new MWException( "Cannot use MWCryptHKDF without a secret." );
-               }
-
-               // In HKDF, the context can be known to the attacker, but this will
-               // keep simultaneous runs from producing the same output.
-               $context = [];
-               $context[] = microtime();
-               $context[] = getmypid();
-               $context[] = gethostname();
-
-               // Setup salt cache
-               $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
-               if ( $cache instanceof EmptyBagOStuff ) {
-                       // Use APC, or fallback to the main cache if it isn't setup
-                       $cache = ObjectCache::getLocalClusterInstance();
-               }
-
-               if ( is_null( self::$singleton ) ) {
-                       self::$singleton = new self( $secret, $wgHKDFAlgorithm, $cache, $context );
-               }
-
-               return self::$singleton;
-       }
-
-       /**
-        * Produce $bytes of secure random data. As a side-effect,
-        * $this->lastK is set to the last hashLen block of key material.
-        * @param int $bytes Number of bytes of data
-        * @param string $context Context to mix into CTXinfo
-        * @return string Binary string of length $bytes
-        */
-       protected function realGenerate( $bytes, $context = '' ) {
-
-               if ( $this->prk === '' ) {
-                       $salt = $this->getSaltUsingCache();
-                       $this->prk = self::HKDFExtract(
-                               $this->algorithm,
-                               $salt,
-                               $this->skm
-                       );
-               }
-
-               $CTXinfo = implode( ':', array_merge( $this->context, [ $context ] ) );
-
-               return self::HKDFExpand(
-                       $this->algorithm,
-                       $this->prk,
-                       $CTXinfo,
-                       $bytes,
-                       $this->lastK
-               );
+               return MediaWikiServices::getInstance()->getCryptHKDF();
        }
 
        /**
@@ -248,62 +72,7 @@ class MWCryptHKDF {
         * @return string Cryptographically secure pseudorandom binary string
         */
        public static function HKDF( $hash, $ikm, $salt, $info, $L ) {
-               $prk = self::HKDFExtract( $hash, $salt, $ikm );
-               $okm = self::HKDFExpand( $hash, $prk, $info, $L );
-               return $okm;
-       }
-
-       /**
-        * Extract the PRK, PRK = HMAC(XTS, SKM)
-        * Note that the hmac is keyed with XTS (the salt),
-        * and the SKM (source key material) is the "data".
-        *
-        * @param string $hash The hashing function to use (e.g., sha256)
-        * @param string $salt The salt to add to the ikm, to get the prk
-        * @param string $ikm The input keying material
-        * @return string Binary string (pseudorandm key) used as input to HKDFExpand
-        */
-       private static function HKDFExtract( $hash, $salt, $ikm ) {
-               return hash_hmac( $hash, $ikm, $salt, true );
-       }
-
-       /**
-        * Expand the key with the given context
-        *
-        * @param string $hash Hashing Algorithm
-        * @param string $prk A pseudorandom key of at least HashLen octets
-        *    (usually, the output from the extract step)
-        * @param string $info Optional context and application specific information
-        *    (can be a zero-length string)
-        * @param int $bytes Length of output keying material in bytes
-        *    (<= 255*HashLen)
-        * @param string &$lastK Set by this function to the last block of the expansion.
-        *    In MediaWiki, this is used to seed future Extractions.
-        * @return string Cryptographically secure random string $bytes long
-        * @throws MWException
-        */
-       private static function HKDFExpand( $hash, $prk, $info, $bytes, &$lastK = '' ) {
-               $hashLen = MWCryptHKDF::$hashLength[$hash];
-               $rounds = ceil( $bytes / $hashLen );
-               $output = '';
-
-               if ( $bytes > 255 * $hashLen ) {
-                       throw new MWException( "Too many bytes requested from HDKFExpand" );
-               }
-
-               // K(1) = HMAC(PRK, CTXinfo || 1);
-               // K(i) = HMAC(PRK, K(i-1) || CTXinfo || i); 1 < i <= t;
-               for ( $counter = 1; $counter <= $rounds; ++$counter ) {
-                       $lastK = hash_hmac(
-                               $hash,
-                               $lastK . $info . chr( $counter ),
-                               $prk,
-                               true
-                       );
-                       $output .= $lastK;
-               }
-
-               return substr( $output, 0, $bytes );
+               return CryptHKDF::HKDF( $hash, $ikm, $salt, $info, $L );
        }
 
        /**
@@ -314,7 +83,7 @@ class MWCryptHKDF {
         * @return string Binary string of length $bytes
         */
        public static function generate( $bytes, $context ) {
-               return self::singleton()->realGenerate( $bytes, $context );
+               return self::singleton()->generate( $bytes, $context );
        }
 
        /**
@@ -327,7 +96,7 @@ class MWCryptHKDF {
         */
        public static function generateHex( $chars, $context = '' ) {
                $bytes = ceil( $chars / 2 );
-               $hex = bin2hex( self::singleton()->realGenerate( $bytes, $context ) );
+               $hex = bin2hex( self::singleton()->generate( $bytes, $context ) );
                return substr( $hex, 0, $chars );
        }
 
diff --git a/includes/utils/MWGrants.php b/includes/utils/MWGrants.php
deleted file mode 100644 (file)
index 58efdc7..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-<?php
-/**
- * Functions and constants to deal with grants
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-/**
- * A collection of public static functions to deal with grants.
- */
-class MWGrants {
-
-       /**
-        * List all known grants.
-        * @return array
-        */
-       public static function getValidGrants() {
-               global $wgGrantPermissions;
-
-               return array_keys( $wgGrantPermissions );
-       }
-
-       /**
-        * Map all grants to corresponding user rights.
-        * @return array grant => array of rights
-        */
-       public static function getRightsByGrant() {
-               global $wgGrantPermissions;
-
-               $res = [];
-               foreach ( $wgGrantPermissions as $grant => $rights ) {
-                       $res[$grant] = array_keys( array_filter( $rights ) );
-               }
-               return $res;
-       }
-
-       /**
-        * Fetch the display name of the grant
-        * @param string $grant
-        * @param Language|string|null $lang
-        * @return string Grant description
-        */
-       public static function grantName( $grant, $lang = null ) {
-               // Give grep a chance to find the usages:
-               // grant-blockusers, grant-createeditmovepage, grant-delete,
-               // grant-editinterface, grant-editmycssjs, grant-editmywatchlist,
-               // grant-editpage, grant-editprotected, grant-highvolume,
-               // grant-oversight, grant-patrol, grant-protect, grant-rollback,
-               // grant-sendemail, grant-uploadeditmovefile, grant-uploadfile,
-               // grant-basic, grant-viewdeleted, grant-viewmywatchlist,
-               // grant-createaccount
-               $msg = wfMessage( "grant-$grant" );
-               if ( $lang !== null ) {
-                       if ( is_string( $lang ) ) {
-                               $lang = Language::factory( $lang );
-                       }
-                       $msg->inLanguage( $lang );
-               }
-               if ( !$msg->exists() ) {
-                       $msg = wfMessage( 'grant-generic', $grant );
-                       if ( $lang ) {
-                               $msg->inLanguage( $lang );
-                       }
-               }
-               return $msg->text();
-       }
-
-       /**
-        * Fetch the display names for the grants.
-        * @param string[] $grants
-        * @param Language|string|null $lang
-        * @return string[] Corresponding grant descriptions
-        */
-       public static function grantNames( array $grants, $lang = null ) {
-               if ( $lang !== null ) {
-                       if ( is_string( $lang ) ) {
-                               $lang = Language::factory( $lang );
-                       }
-               }
-
-               $ret = [];
-               foreach ( $grants as $grant ) {
-                       $ret[] = self::grantName( $grant, $lang );
-               }
-               return $ret;
-       }
-
-       /**
-        * Fetch the rights allowed by a set of grants.
-        * @param string[]|string $grants
-        * @return string[]
-        */
-       public static function getGrantRights( $grants ) {
-               global $wgGrantPermissions;
-
-               $rights = [];
-               foreach ( (array)$grants as $grant ) {
-                       if ( isset( $wgGrantPermissions[$grant] ) ) {
-                               $rights = array_merge( $rights, array_keys( array_filter( $wgGrantPermissions[$grant] ) ) );
-                       }
-               }
-               return array_unique( $rights );
-       }
-
-       /**
-        * Test that all grants in the list are known.
-        * @param string[] $grants
-        * @return bool
-        */
-       public static function grantsAreValid( array $grants ) {
-               return array_diff( $grants, self::getValidGrants() ) === [];
-       }
-
-       /**
-        * Divide the grants into groups.
-        * @param string[]|null $grantsFilter
-        * @return array Map of (group => (grant list))
-        */
-       public static function getGrantGroups( $grantsFilter = null ) {
-               global $wgGrantPermissions, $wgGrantPermissionGroups;
-
-               if ( is_array( $grantsFilter ) ) {
-                       $grantsFilter = array_flip( $grantsFilter );
-               }
-
-               $groups = [];
-               foreach ( $wgGrantPermissions as $grant => $rights ) {
-                       if ( $grantsFilter !== null && !isset( $grantsFilter[$grant] ) ) {
-                               continue;
-                       }
-                       if ( isset( $wgGrantPermissionGroups[$grant] ) ) {
-                               $groups[$wgGrantPermissionGroups[$grant]][] = $grant;
-                       } else {
-                               $groups['other'][] = $grant;
-                       }
-               }
-
-               return $groups;
-       }
-
-       /**
-        * Get the list of grants that are hidden and should always be granted
-        * @return string[]
-        */
-       public static function getHiddenGrants() {
-               global $wgGrantPermissionGroups;
-
-               $grants = [];
-               foreach ( $wgGrantPermissionGroups as $grant => $group ) {
-                       if ( $group === 'hidden' ) {
-                               $grants[] = $grant;
-                       }
-               }
-               return $grants;
-       }
-
-       /**
-        * Generate a link to Special:ListGrants for a particular grant name.
-        *
-        * This should be used to link end users to a full description of what
-        * rights they are giving when they authorize a grant.
-        *
-        * @param string $grant the grant name
-        * @param Language|string|null $lang
-        * @return string (proto-relative) HTML link
-        */
-       public static function getGrantsLink( $grant, $lang = null ) {
-               return \Linker::linkKnown(
-                       \SpecialPage::getTitleFor( 'Listgrants', false, $grant ),
-                       htmlspecialchars( self::grantName( $grant, $lang ) )
-               );
-       }
-
-       /**
-        * Generate wikitext to display a list of grants
-        * @param string[]|null $grantsFilter If non-null, only display these grants.
-        * @param Language|string|null $lang
-        * @return string Wikitext
-        */
-       public static function getGrantsWikiText( $grantsFilter, $lang = null ) {
-               global $wgContLang;
-
-               if ( is_string( $lang ) ) {
-                       $lang = Language::factory( $lang );
-               } elseif ( $lang === null ) {
-                       $lang = $wgContLang;
-               }
-
-               $s = '';
-               foreach ( self::getGrantGroups( $grantsFilter ) as $group => $grants ) {
-                       if ( $group === 'hidden' ) {
-                               continue; // implicitly granted
-                       }
-                       $s .= "*<span class=\"mw-grantgroup\">" .
-                               wfMessage( "grant-group-$group" )->inLanguage( $lang )->text() . "</span>\n";
-                       $s .= ":" . $lang->semicolonList( self::grantNames( $grants, $lang ) ) . "\n";
-               }
-               return "$s\n";
-       }
-
-}
diff --git a/includes/utils/iterators/IteratorDecorator.php b/includes/utils/iterators/IteratorDecorator.php
deleted file mode 100644 (file)
index c1b5020..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-/**
- * Allows extending classes to decorate an Iterator with
- * reduced boilerplate.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-abstract class IteratorDecorator implements Iterator {
-       protected $iterator;
-
-       public function __construct( Iterator $iterator ) {
-               $this->iterator = $iterator;
-       }
-
-       public function current() {
-               return $this->iterator->current();
-       }
-
-       public function key() {
-               return $this->iterator->key();
-       }
-
-       public function next() {
-               $this->iterator->next();
-       }
-
-       public function rewind() {
-               $this->iterator->rewind();
-       }
-
-       public function valid() {
-               return $this->iterator->valid();
-       }
-}
diff --git a/includes/utils/iterators/NotRecursiveIterator.php b/includes/utils/iterators/NotRecursiveIterator.php
deleted file mode 100644 (file)
index 52ca61b..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/**
- * Wraps a non-recursive iterator with methods to be recursive
- * without children.
- *
- * Alternatively wraps a recursive iterator to prevent recursing deeper
- * than the wrapped iterator.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-class NotRecursiveIterator extends IteratorDecorator implements RecursiveIterator {
-       public function hasChildren() {
-               return false;
-       }
-
-       public function getChildren() {
-               return null;
-       }
-}
index 6e8cdb6..865a51e 100644 (file)
        "movelogpagetext": "Esta ye la llista de páxines treslladaes.",
        "movesubpage": "{{PLURAL:$1|Subpáxina|Subpáxines}}",
        "movesubpagetext": "Esta páxina tien $1 {{PLURAL:$1|subpáxina|subpáxines}} que s'amuesen darréu.",
+       "movesubpagetalktext": "La páxina d'alderique correspondiente tien $1 {{PLURAL:$1|subpáxina|subpáxines}} que {{PLURAL:$1|s'amuesa|s'amuesen}} darréu.",
        "movenosubpage": "Esta páxina nun tien subpáxines.",
        "movereason": "Motivu:",
        "revertmove": "revertir",
        "newimages-showbots": "Ver les xubíes de los bots",
        "newimages-hidepatrolled": "Despintar les entraes patrullaes",
        "noimages": "Nun hai nada que ver.",
+       "gallery-slideshow-toggle": "Intercambiar les miniatures",
        "ilsubmit": "Guetar",
        "bydate": "por fecha",
        "sp-newimages-showfrom": "Amosar los archivos nuevos emprimando dende'l $1 a les $2",
        "feedback-thanks": "¡Gracies! La to opinión s'espublizó na páxina «[$2  $1]».",
        "feedback-thanks-title": "¡Gracies!",
        "feedback-useragent": "Axente d'usuariu:",
-       "searchsuggest-search": "Buscar",
+       "searchsuggest-search": "Buscar en {{SITENAME}}",
        "searchsuggest-containing": "que contien...",
        "api-error-autoblocked": "La to dirección IP bloquióse automáticamente porque la usó un usuariu bloquiáu.",
        "api-error-badaccess-groups": "Nun tienes permisu pa xubir ficheros a esta wiki.",
        "usercssispublic": "Atención: les subpáxines CSS nun tendríen de contener datos acutaos porque son visibles pa otros usuarios.",
        "restrictionsfield-badip": "Direición o rangu IP inválidu: $1",
        "restrictionsfield-label": "Rangos d'IP permitíos:",
-       "restrictionsfield-help": "Una única direición IP o rangu CIDR per llinia. P'activar toos, utiliza<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "Una única direición IP o rangu CIDR per llinia. P'activar toos, utiliza<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Error: $1",
+       "edit-error-long": "Errores:\n\n$1"
 }
index 95071ab..7077396 100644 (file)
        "newimages-showbots": "Паказаць загружаныя робатамі",
        "newimages-hidepatrolled": "Схаваць патруляваныя загрузкі",
        "noimages": "Выявы адсутнічаюць.",
+       "gallery-slideshow-toggle": "Пераключыць мініятуры",
        "ilsubmit": "Шукаць",
        "bydate": "па даце",
        "sp-newimages-showfrom": "Паказаць новыя файлы, загружаныя пазьней за $2, $1",
        "feedback-thanks": "Дзякуй! Ваш водгук быў разьмешчаны на старонцы «[$2 $1]».",
        "feedback-thanks-title": "Дзякуй!",
        "feedback-useragent": "Агент удзельніка:",
-       "searchsuggest-search": "Пошук",
+       "searchsuggest-search": "Пошук у {{GRAMMAR:месны|{{SITENAME}}}}",
        "searchsuggest-containing": "утрымлівае...",
        "api-error-autoblocked": "Ваш IP-адрас быў аўтаматычна заблякаваны, бо ён быў выкарыстаны заблякаваным удзельнікам.",
        "api-error-badaccess-groups": "У Вас няма дазволу загружаць файлы ў гэтую вікі.",
index ae72494..2b1c8f6 100644 (file)
        "ilsubmit": "অনুসন্ধান",
        "bydate": "তারিখ অনুযায়ী",
        "sp-newimages-showfrom": "$2, $1 এর পরের নতুন ছবিগুলো দেখাও",
+       "seconds-abbrev": "$1 সে",
        "minutes-abbrev": "$1 মিনিট",
+       "hours-abbrev": "$1 ঘ",
+       "days-abbrev": "$1 দিন",
        "seconds": "{{PLURAL:$1|$1 সেকেন্ড|$1 সেকেন্ড}}",
        "minutes": "{{PLURAL:$1|$1 মিনিট|$1 মিনিট}}",
        "hours": "{{PLURAL:$1|$1 ঘণ্টা|$1 ঘণ্টা}}",
        "feedback-thanks": "ধন্যবাদ! আপনার প্রতিক্রিয়া \"[$2 $1]\" পাতায় পোস্ট করা হয়েছে।",
        "feedback-thanks-title": "আপনাকে ধন্যবাদ!",
        "feedback-useragent": "ব্যবহারকারী এজেন্ট:",
-       "searchsuggest-search": "অনুসন্ধান",
+       "searchsuggest-search": "{{SITENAME}} অনুসন্ধান",
        "searchsuggest-containing": "যা আছে...",
        "api-error-badaccess-groups": "আপনার এই উইকিতে ফাইল আপলোডের অনুমতি নেই।",
        "api-error-badtoken": "অভ্যন্তরীণ ত্রুটি: খারাপ টোকেন।",
        "usercssispublic": "অনুগ্রহ করে লক্ষ্য করুন: সিএসএসের উপপাতাগুলিতে গোপনীয় তথ্য থাকা উচিত নয় যেহেতু অন্যান্য ব্যবহারকারীও এগুলি দেখতে পান।",
        "restrictionsfield-badip": "আইপি ঠিকানা অথবা পরিসীমা অবৈধ: $1",
        "restrictionsfield-label": "অনুমোদিত আইপি পরিসীমা:",
-       "restrictionsfield-help": "লাইন প্রতি একটি আইপি ঠিকানা বা CIDR পরিসীমা। সবকিছু সক্রিয় করতে<br><code>0.0.0.0/0</code><br><code>::/0</code><br>ব্যবহার করুন"
+       "restrictionsfield-help": "লাইন প্রতি একটি আইপি ঠিকানা বা CIDR পরিসীমা। সবকিছু সক্রিয় করতে<br><code>0.0.0.0/0</code><br><code>::/0</code><br>ব্যবহার করুন",
+       "edit-error-short": "ত্রুটি: $1",
+       "edit-error-long": "ত্রুটিসমূহ:\n\n$1"
 }
index 1c3ddf7..82163eb 100644 (file)
@@ -83,7 +83,7 @@
        "tog-enotifminoredits": "Notifica'm per correu també en casos d'edicions menors",
        "tog-enotifrevealaddr": "Mostra la meua adreça electrònica en els missatges d'avís per correu",
        "tog-shownumberswatching": "Mostra el nombre d'usuaris que hi vigilen",
-       "tog-oldsig": "Signatura actual:",
+       "tog-oldsig": "La vostra signatura actual:",
        "tog-fancysig": "Tractar la signatura com a text wiki (sense enllaç automàtic)",
        "tog-uselivepreview": "Utilitza la previsualització automàtica",
        "tog-forceeditsummary": "Avisa'm en deixar el resum de la modificació en blanc",
        "newwindow": "(obre en una nova finestra)",
        "cancel": "Cancel·la",
        "moredotdotdot": "Més...",
-       "morenotlisted": "Aquesta llista no és completa.",
+       "morenotlisted": "Aquesta llista pot ser incompleta.",
        "mypage": "Pàgina",
        "mytalk": "Discussió",
        "anontalk": "Discussió",
        "talk": "Discussió",
        "views": "Vistes",
        "toolbox": "Eines",
+       "tool-link-userrights": "Canvia els grups de l'{{GENDER:$1|usuari|usuària}}",
+       "tool-link-emailuser": "Envia un missatge electrònic a l'{{GENDER:$1|usuari|usuària}}",
        "userpage": "Visualitza la pàgina d'usuari",
        "projectpage": "Visualitza la pàgina del projecte",
        "imagepage": "Visualitza la pàgina del fitxer",
        "createacct-yourpasswordagain-ph": "Introduïu de nou la contrasenya",
        "userlogin-remembermypassword": "Mantén-me connectat",
        "userlogin-signwithsecure": "Connexió segura",
+       "cannotlogin-title": "No es pot iniciar la sessió",
+       "cannotlogin-text": "No és possible iniciar la sessió.",
        "cannotloginnow-title": "Ara no es pot iniciar la sessió",
        "cannotloginnow-text": "No es pot iniciar la sessió quan s'utilitza $1.",
+       "cannotcreateaccount-title": "No es poden crear comptes",
+       "cannotcreateaccount-text": "La creació de comptes directa no està habilitada en aquest wiki.",
        "yourdomainname": "El vostre domini",
        "password-change-forbidden": "No podeu canviar les contrasenyes en aquest wiki.",
        "externaldberror": "Hi ha hagut un error en la base de dades d'autenticació o bé no teniu permís per a actualitzar el vostre compte extern.",
        "mergehistory-fail-bad-timestamp": "La marca horària no és vàlida.",
        "mergehistory-fail-invalid-source": "La pàgina font no és vàlida.",
        "mergehistory-fail-invalid-dest": "La pàgina de destinació no és vàlida.",
+       "mergehistory-fail-permission": "No hi ha permisos suficients per fusionar l'historial.",
        "mergehistory-fail-self-merge": "Les pàgines d'origen i de destinació no poden ser la mateixa",
        "mergehistory-fail-toobig": "No s'ha pogut fer la fusió de l'historial perquè es mourien més del límit de $1 {{PLURAL:$1|revisió|revisions}}.",
        "mergehistory-no-source": "La pàgina d'origen $1 no existeix.",
        "grant-group-file-interaction": "Interacció amb fitxes multimèdia",
        "grant-group-watchlist-interaction": "Interacció amb la vostra llista de seguiment",
        "grant-group-email": "Enviament de correu",
+       "grant-group-high-volume": "Realitzeu activat d'alt volum",
        "grant-group-customization": "Personalització i preferències",
        "grant-group-administration": "Realitza accions administratives",
        "grant-group-other": "Activitat miscel·lània",
        "grant-highvolume": "Edició d'alt volum",
        "grant-oversight": "Amaga usuaris i suprimeix revisions",
        "grant-patrol": "Patrulla els canvis de les pàgines",
+       "grant-privateinfo": "Accedeix a informació privada",
        "grant-protect": "Protecció i desprotecció de pàgines",
        "grant-rollback": "Reversió de canvis en pàgines",
        "grant-sendemail": "Enviament de correus a altres usuaris",
        "file-thumbnail-no": "El nom del fitxer comença per <strong>$1</strong>.\nSembla una imatge de mida reduïda <em>(miniatura)</em>.\nSi teniu la imatge en alta resolució, pugeu-la. Si no, mireu de canviar-li el nom.",
        "fileexists-forbidden": "Ja hi existeix un fitxer amb aquest nom i no es pot sobreescriure.\nSi us plau, torneu enrere i carregueu aquest fitxer sota un altre nom. [[File:$1|thumb|center|$1]]",
        "fileexists-shared-forbidden": "Ja hi ha un fitxer amb aquest nom en el fons comú de fitxers.\nSi encara voleu pujar el fitxer, torneu enrere i pugeu-ne una còpia amb un altre nom. [[File:$1|thumb|center|$1]]",
+       "fileexists-no-change": "La càrrega és un duplicat exacte de la versió actual de <strong>[[:$1]]</strong>.",
        "file-exists-duplicate": "Aquest fitxer és un duplicat {{PLURAL:$1|del fitxer |dels següents fitxers:}}",
        "file-deleted-duplicate": "S'ha suprimit anteriorment un fitxer idèntic a aquest ([[:$1]]). Hauríeu de comprovar el registre de supressions del fitxer abans de tornar-lo a carregar.",
        "file-deleted-duplicate-notitle": "Un fitxer idèntic a aquest fitxer havia estat suprimit abans, i també el títol. Hauríeu de demanar a algú que pugui veure les dades suprimides del fitxer que revisi la situació abans de procedir a tornar a carregar-lo.",
        "upload-dialog-disabled": "La càrrega de fitxers utilitzant aquest quadre de diàleg està desactivada en aquest wiki.",
        "upload-dialog-title": "Carrega un fitxer",
        "upload-dialog-button-cancel": "Cancel·la",
+       "upload-dialog-button-back": "Enrere",
        "upload-dialog-button-done": "Fet",
        "upload-dialog-button-save": "Desa",
        "upload-dialog-button-upload": "Carrega",
        "apisandbox-results": "Resultats",
        "apisandbox-request-url-label": "Sol·licita URL:",
        "apisandbox-request-time": "Temps de sol·licitud: {{PLURAL:$1|$1 ms}}",
+       "apisandbox-continue": "Continua",
+       "apisandbox-continue-clear": "Neteja",
        "booksources": "Obres de referència",
        "booksources-search-legend": "Cerca fonts de llibres",
        "booksources-isbn": "ISBN:",
        "ipb-unblock": "Desbloca un usuari o una adreça IP",
        "ipb-blocklist": "Llista els bloquejos existents",
        "ipb-blocklist-contribs": "Contribucions de {{GENDER:$1|$1}}",
+       "ipb-blocklist-duration-left": "$1 restant",
        "unblockip": "Desbloca l'usuari",
        "unblockiptext": "Empreu el següent formulari per restaurar\nl'accés a l'escriptura a una adreça IP o un usuari prèviament bloquejat.",
        "ipusubmit": "Desbloca aquesta adreça",
        "pageinfo-article-id": "ID de la pàgina",
        "pageinfo-language": "Llengua del contingut de la pàgina",
        "pageinfo-content-model": "Plantilla de contingut de pàgina",
+       "pageinfo-content-model-change": "canvia",
        "pageinfo-robot-policy": "Indexació per robots",
        "pageinfo-robot-index": "Permès",
        "pageinfo-robot-noindex": "No permès",
        "newimages-showbots": "Mostra les càrregues dels bots",
        "newimages-hidepatrolled": "Amaga les càrregues patrullades",
        "noimages": "Res per veure.",
+       "gallery-slideshow-toggle": "Canvia les miniatures",
        "ilsubmit": "Cerca",
        "bydate": "per data",
        "sp-newimages-showfrom": "Mostra fitxers nous des del $1 a les $2",
        "htmlform-cloner-create": "Afegeix més",
        "htmlform-cloner-delete": "Suprimeix",
        "htmlform-cloner-required": "Cal com a mínim un valor.",
+       "htmlform-time-placeholder": "HH:MM:SS",
        "htmlform-title-badnamespace": "[[:$1]] no es troba en l'espai de noms \"{{ns:$2}}\".",
        "htmlform-title-not-creatable": "\"$1\" és un títol de pàgina no editable",
        "htmlform-title-not-exists": "$1 no existeix.",
        "feedback-external-bug-report-button": "Arxiva una tasca tècnica",
        "feedback-dialog-title": "Envia el comentari",
        "feedback-dialog-intro": "Podeu utilitzar el senzill formulari de sota per a trametre la vostra opinió. El comentari s'afegirà a la pàgina «$1» juntament amb el vostre nom d'usuari.",
-       "feedback-error-title": "Error",
        "feedback-error1": "Error: Resultat de l'API no reconegut",
        "feedback-error2": "Error: Edició fallida",
        "feedback-error3": "Error: No hi ha resposta de l'API",
        "feedback-thanks": "Gràcies! S'ha publicat la vostra opinió a la pàgina «[$2 $1]».",
        "feedback-thanks-title": "Gràcies!",
        "feedback-useragent": "Agent d'usuari:",
-       "searchsuggest-search": "Cerca",
+       "searchsuggest-search": "Cerca a {{SITENAME}}",
        "searchsuggest-containing": "que conté ...",
+       "api-error-autoblocked": "S'ha blocat la vostra IP automàticament perquè la va utilitzar un usuari blocat.",
        "api-error-badaccess-groups": "No teniu permís per a carregar fitxers en aquest wiki.",
        "api-error-badtoken": "Error intern: argument incorrecte.",
        "api-error-copyuploaddisabled": "Les càrregues via URL estan desactivades en aquest servidor.",
        "log-action-filter-protect-protect": "Protecció",
        "log-action-filter-protect-modify": "Modificació de la protecció",
        "log-action-filter-protect-unprotect": "Desprotecció",
+       "log-action-filter-rights-rights": "Canvi manual",
+       "log-action-filter-rights-autopromote": "Canvi automàtic",
+       "log-action-filter-suppress-event": "Supressió de registres",
+       "log-action-filter-suppress-revision": "Supressió de revisions",
+       "log-action-filter-suppress-delete": "Supressió de pàgines",
        "log-action-filter-upload-upload": "Nova càrrega",
        "log-action-filter-upload-overwrite": "Torna a carregar",
        "authmanager-authn-not-in-progress": "L'autenticació no està en curs o les dades de sessió s'han perdut. Comenceu de nou des del principi.",
        "authmanager-authn-no-primary": "Les dades credencials no s'han pogut autenticar.",
        "authmanager-authn-autocreate-failed": "Ha fallat la creació automàtica d'un compte local: $1",
+       "authmanager-create-disabled": "S'ha inhabilitat la creació de comptes.",
+       "authmanager-create-from-login": "Per crear un compte, ompliu els camps de sota.",
+       "authmanager-authplugin-setpass-bad-domain": "Domini invàlid.",
+       "authmanager-retype-help": "Contrasenya de nou per confirmar",
+       "authmanager-email-label": "Correu electrònic",
+       "authmanager-email-help": "Adreça electrònica",
        "authmanager-realname-label": "Nom real",
        "authmanager-realname-help": "Nom real de l'usuari",
+       "authmanager-provider-password": "Autenticació basada en contrasenya",
+       "authmanager-provider-password-domain": "Autenticació basada en contrasenya i en domini",
        "authmanager-provider-temporarypassword": "Contrasenya temporal",
        "authprovider-resetpass-skip-label": "Omet",
+       "specialpage-securitylevel-not-allowed-title": "No permès",
        "authpage-cannot-login-continue": "No es pot continuar amb l'inicio de sessió. Probablement la vostra sessió ha expirat.",
        "authpage-cannot-create-continue": "No es pot prosseguir la creació del compte. Probablement la vostra sessió ha expirat.",
        "changecredentials": "Canvi de dades credencials",
        "changecredentials-submit": "Canvia les dades credencials",
        "credentialsform-provider": "Tipus de dades credencials:",
        "credentialsform-account": "Nom del compte:",
+       "linkaccounts": "Enllaça els comptes",
+       "linkaccounts-success-text": "S'ha enllaçat el compte.",
        "linkaccounts-submit": "Enllaça els comptes",
        "unlinkaccounts": "Desenllaça els comptes",
        "unlinkaccounts-success": "El compte s'ha desenllaçat.",
index fafca4a..e4ed07f 100644 (file)
@@ -55,7 +55,7 @@
        "tog-showhiddencats": "㪗藏類別",
        "tog-norollbackdiff": "Cék-hèng huòi-gūng ī-hâiu ng-sāi hiēng-sê chă-biék",
        "tog-useeditwarning": "我編輯頁面其時候離開,起動警告我蜀下",
-       "tog-prefershttps": "Láuk-diē ī-hâiu sṳ̄-cṳ̆ng sāi ăng-cuòng lièng-giék",
+       "tog-prefershttps": "Láuk-diē ī-hâiu tié-lāu sāi ăng-ciòng lièng-giék",
        "underline-always": "直頭",
        "underline-never": "頭𡅏無",
        "underline-default": "皮膚或者瀏覽器默認其",
        "december-date": "十二月$1號",
        "period-am": "AM",
        "period-pm": "PM",
-       "pagecategories": "{{PLURAL:$1}} Lôi-biék",
+       "pagecategories": "{{PLURAL:$1|Lôi-biék}}",
        "category_header": "「$1」類別下底其頁面",
        "subcategories": "子類別",
        "category-media-header": "「$1」類別下底其媒體",
        "morenotlisted": "Ciā dăng-dăng mâ̤ uòng-cīng.",
        "mypage": "頁面",
        "mytalk": "我其討論",
-       "anontalk": "Páng-gōng",
+       "anontalk": "Păng-gōng",
        "navigation": "Īng-dô̤:",
        "and": "&#32;gâe̤ng",
        "qbfind": "討",
        "redirectedfrom": "(téng $1 tṳ̀ng-déng-hióng guó-lì)",
        "redirectpagesub": "重定向頁",
        "redirectto": "重定向遘",
-       "lastmodifiedat": "Cī siŏh hiĕh sê diŏh $1 $2 sèng-hâiu có̤i-âu siŭ-gāi gì.",
+       "lastmodifiedat": "Cī siŏh hiĕk sê diŏh $1 $2 sèng-hâiu có̤i-hâiu siŭ-gāi gì.",
        "viewcount": "茲蜀頁已經乞訪問$1回了。{{PLURAL:$1}}",
        "protectedpage": "保護頁",
        "jumpto": "Tiéu gáu:",
        "site-atom-feed": "$1 Atom déng-iŏk",
        "page-rss-feed": "「$1」RSS訂閱",
        "page-atom-feed": "$1 Atom déng-iŏk",
-       "red-link-title": "$1 (mò̤ hī hiĕh)",
+       "red-link-title": "$1 (mò̤ hī hiĕk)",
        "sort-descending": "降序排序",
        "sort-ascending": "升序排序",
        "nstab-main": "Ùng-ciŏng",
        "thumbnail-more": "Huóng-duâi",
        "tooltip-pt-userpage": "汝其用戶頁",
        "tooltip-pt-mytalk": "汝其討論頁",
+       "tooltip-pt-anontalk": "Cī ciáh IP ôi-cī iū-guăng siŭ-gāi gì tō̤-lâung",
        "tooltip-pt-preferences": "汝其設定",
        "tooltip-pt-watchlist": "汝監視其頁面有改過其單單",
        "tooltip-pt-mycontris": "汝其貢獻其單單",
        "tooltip-n-recentchanges": "Cī-bŏng diŏh wiki ô gāi-biéng gì dăng-dăng",
        "tooltip-n-randompage": "Sùi-biêng muōng ché̤ṳ",
        "tooltip-n-help": "Sìng-tō̤ bŏng-cô gì sū-câi",
-       "tooltip-t-whatlinkshere": "Cuòng-buô lièng-gáu cŭ-uái gì wiki hiĕk-miêng dăng-dăng",
+       "tooltip-t-whatlinkshere": "Ciòng-buô lièng-gáu cŭ-uái gì wiki hiĕk-miêng dăng-dăng",
        "tooltip-t-recentchangeslinked": "鏈遘茲頁其頁面其最近修改\nCī hiĕk lièng gáu bĕk hiĕk gì cī-bŏng gì gāi-biéng",
        "tooltip-t-contributions": "茲蜀用戶其貢獻單單",
        "tooltip-t-emailuser": "向茲蜀隻用戶寄電批",
        "exif-meteringmode-0": "𣍐八",
        "exif-lightsource-0": "𣍐八",
        "exif-subjectdistancerange-0": "𣍐八",
-       "namespacesall": "cuòng-buô",
+       "namespacesall": "ciòng-buô",
        "monthsall": "囫圇年",
        "confirmemail": "確定電批地址",
        "confirmemail_invalid": "確認碼無效。\n可能已經過期了。",
index bcd4b49..ddced48 100644 (file)
        "rightslog": "Къулланыджынынъ акълары журналы",
        "action-edit": "бу саифени денъиштирмеге",
        "nchanges": "$1 {{PLURAL:$1|денъиштирме}}",
+       "enhancedrc-history": "тарих",
        "recentchanges": "Сонъки денъиштирмелер",
        "recentchanges-legend": "Сонъки денъиштирмелер сазламалары",
        "recentchanges-summary": "Япылгъан энъ сонъки денъиштирмелерни бу саифеде корип оласынъыз.",
index 964df5c..e96da64 100644 (file)
        "feedback-thanks": "Děkujeme! Váš komentář byl přidán na stránku „[$2 $1]“.",
        "feedback-thanks-title": "Děkujeme!",
        "feedback-useragent": "Uživatelský agent:",
-       "searchsuggest-search": "Hledat",
+       "searchsuggest-search": "Hledat na {{GRAMMAR:6sg|{{SITENAME}}}}",
        "searchsuggest-containing": "obsahující…",
        "api-error-autoblocked": "Vaše IP adresa byla automaticky zablokována, protože ji používal zablokovaný uživatel.",
        "api-error-badaccess-groups": "Nemáte povoleno nahrávat soubory na tuto wiki.",
index 445a13d..243f55a 100644 (file)
        "movelogpagetext": "Dies ist eine Liste aller verschobenen Seiten.",
        "movesubpage": "{{PLURAL:$1|Unterseite|Unterseiten}}",
        "movesubpagetext": "Diese Seite hat $1 {{PLURAL:$1|Unterseite|Unterseiten}}.",
+       "movesubpagetalktext": "Die dazugehörige Diskussionsseite hat {{PLURAL:$1|eine Unterseite, die unten angezeigt wird|$1 Unterseiten, die unten angezeigt werden}}.",
        "movenosubpage": "Diese Seite hat keine Unterseiten.",
        "movereason": "Grund:",
        "revertmove": "zurück verschieben",
        "usercssispublic": "Bitte beachten: CSS-Unterseiten sollten keine vertraulichen Daten enthalten, da sie von anderen Benutzern eingesehen werden können.",
        "restrictionsfield-badip": "Ungültige IP-Adresse oder ungültiger IP-Adressbereich: $1",
        "restrictionsfield-label": "Erlaubte IP-Adressbereiche:",
-       "restrictionsfield-help": "Eine IP-Adresse oder ein CIDR-Bereich pro Zeile. Um alles zu aktivieren, verwende<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "Eine IP-Adresse oder ein CIDR-Bereich pro Zeile. Um alles zu aktivieren, verwende<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Fehler: $1",
+       "edit-error-long": "Fehler:\n\n$1"
 }
index d3db938..cd9fd62 100644 (file)
@@ -25,7 +25,8 @@
                        "Matma Rex",
                        "Kumkumuk",
                        "Gırd",
-                       "Velg"
+                       "Velg",
+                       "1917 Ekim Devrimi"
                ]
        },
        "tog-underline": "Bınê gırey de xete bance:",
        "specialpage": "Pela xısusiye",
        "personaltools": "Hacetê şexsiy",
        "articlepage": "Pera zerreki bıvin",
-       "talk": "Vacenayış",
+       "talk": "Werênayış",
        "views": "Asayışi",
        "toolbox": "Haceti",
        "tool-link-userrights": "Grubanê {{GENDER:$1|karberi}} bıvırnë",
        "viewhelppage": "Pera peşti bıvin",
        "categorypage": "Pela kategoriya bıasne",
        "viewtalkpage": "Werênayışi bıvêne",
-       "otherlanguages": "Zıwananê binan de",
+       "otherlanguages": "Zederna zıwani",
        "redirectedfrom": "($1 ra kırışı yê)",
        "redirectpagesub": "Pela berdışi",
        "redirectto": "Beno hetê:",
index 30adf58..f30c038 100644 (file)
        "movelogpagetext": "Below is a list of all page moves.",
        "movesubpage": "{{PLURAL:$1|Subpage|Subpages}}",
        "movesubpagetext": "This page has $1 {{PLURAL:$1|subpage|subpages}} shown below.",
+       "movesubpagetalktext": "The corresponding talk page has $1 {{PLURAL:$1|subpage|subpages}} shown below.",
        "movenosubpage": "This page has no subpages.",
        "movereason": "Reason:",
        "move-redirect-text": "",
        "usercssispublic": "Please note: CSS subpages should not contain confidential data as they are viewable by other users.",
        "restrictionsfield-badip": "Invalid IP address or range: $1",
        "restrictionsfield-label": "Allowed IP ranges:",
-       "restrictionsfield-help": "One IP address or CIDR range per line. To enable everything, use<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "One IP address or CIDR range per line. To enable everything, use<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Error: $1",
+       "edit-error-long": "Errors:\n\n$1"
 }
index efd19f3..bb43a09 100644 (file)
        "eauthentsent": "Se ha enviado un correo electrónico de confirmación a la dirección especificada.\nAntes de que se envíe cualquier otro correo a la cuenta tienes que seguir las instrucciones enviadas en el mensaje para así confirmar que la dirección te pertenece.",
        "throttled-mailpassword": "Ya se ha enviado un recordatorio de contraseña en {{PLURAL:$1|la última hora|las últimas $1 horas}}.\nPara evitar los abusos, solo se enviará un recordatorio de contraseña cada {{PLURAL:$1|hora|$1 horas}}.",
        "mailerror": "Error al enviar el mensaje: $1",
-       "acct_creation_throttle_hit": "Los visitantes a este wiki usando tu dirección IP han creado {{PLURAL:$1|una cuenta|$1 cuentas}} en el último $2, lo cual es lo máximo permitido en este periodo de tiempo.\nComo resultado, los visitantes usando esta dirección IP no pueden crear más cuentas en este momento.",
+       "acct_creation_throttle_hit": "Por medio de tu dirección IP ya {{PLURAL:$1|se ha creado una cuenta|se han creado $1 cuentas}} durante $2, lo cual es lo máximo permitido por este período de tiempo.\nPor este motivo, desde esta dirección IP no se pueden crear más cuentas por el momento.",
        "emailauthenticated": "Tu dirección de correo electrónico fue confirmada el $2 a las $3.",
        "emailnotauthenticated": "Aún no has confirmado tu dirección de correo electrónico.\nHasta que lo hagas, las siguientes funciones no estarán disponibles.",
        "noemailprefs": "Especifica una dirección electrónica para habilitar estas características.",
        "passwordreset-emailelement": "Nombre de {{GENDER:$1|usuario|usuaria}}: \n$1\n\nContraseña temporal: \n$2",
        "passwordreset-emailsentemail": "Si esta dirección de correo electrónico está asociada a tu cuenta, entonces se enviará un correo electrónico para restablecer la contraseña.",
        "passwordreset-emailsentusername": "Si existe una dirección de correo electrónico asociada a este nombre de usuario, entonces se enviará un correo para restablecer la contraseña.",
-       "passwordreset-emailsent-capture2": "{{PLURAL:$1|El e-mail de restablecimiento de contraseña ha sido enviado|Los e-mails de restablecimiento de contraseña han sido enviados}}. {{PLURAL:$1|El nombre de usuario y la contraseña se muestra|La lista de nombres de usuarios y contraseñas se muestra}} aquí.",
+       "passwordreset-emailsent-capture2": "{{PLURAL:$1|Se ha enviado el mensaje de restablecimiento de contraseña|Se han enviado los mensajes de restablecimiento de contraseña}}. {{PLURAL:$1|El nombre de usuario y la contraseña|La lista de nombres de usuarios y contraseñas}} se muestra aquí.",
        "passwordreset-emailerror-capture2": "No fue posible mandar un correo electrónico {{GENDER:$2|al usuario|a la usuaria}}: $1 {{PLURAL:$3|El nombre de usuario y la contraseña|La lista de nombres de usuarios y contraseñas}} se muestra aquí.",
        "passwordreset-nocaller": "Debe de proporcionarse un interlocutor",
        "passwordreset-nosuchcaller": "La persona que llama no existe: $1",
        "invalid-content-data": "Datos de contenido incorrectos",
        "content-not-allowed-here": "El contenido «$1» no está permitido en la página [[$2]]",
        "editwarning-warning": "Se perderán los cambios si se cierra esta página.\nSi has iniciado sesión, puedes desactivar este aviso en la sección «{{int:prefs-editing}}» de las preferencias.",
-       "editpage-invalidcontentmodel-title": "Modelo de contenido no soportado",
-       "editpage-invalidcontentmodel-text": "El modelo de contenido \"$1\" no se admite.",
+       "editpage-invalidcontentmodel-title": "Modelo de contenido no admitido",
+       "editpage-invalidcontentmodel-text": "El modelo de contenido «$1» no se admite.",
        "editpage-notsupportedcontentformat-title": "Formato de contenido no compatible",
        "editpage-notsupportedcontentformat-text": "El formato de contenido $1 no es compatible con el modelo de contenido $2.",
        "content-model-wikitext": "texto wiki",
        "feedback-thanks": "¡Gracias! Tus comentarios se han publicado en la página \"[$2 $1]\".",
        "feedback-thanks-title": "¡Muchas gracias!",
        "feedback-useragent": "Agente de usuario:",
-       "searchsuggest-search": "Buscar",
+       "searchsuggest-search": "Buscar en {{SITENAME}}",
        "searchsuggest-containing": "que contiene...",
        "api-error-autoblocked": "Tu dirección IP ha sido bloqueada automáticamente porque fue utilizada por un usuario bloqueado.",
        "api-error-badaccess-groups": "No puedes cargar archivos en este wiki.",
        "authenticationdatachange-ignored": "El cambio den los datos de autentificacion no fue realizado. ¿Tal vez, no se configuró un proveedor?",
        "userjsispublic": "Recuerda: las subpáginas JavaScript no deberían contener datos confidenciales, pues otros usuarios los pueden ver.",
        "usercssispublic": "Recuerda: las subpáginas CSS no deberían contener datos confidenciales, pues otros usuarios los pueden ver.",
-       "restrictionsfield-badip": "Dirección IP o rango inválido: $1",
-       "restrictionsfield-label": "Rangos de IP permitidos:"
+       "restrictionsfield-badip": "Dirección o intervalo IP no válidos: $1",
+       "restrictionsfield-label": "Intervalos de IP permitidos:"
 }
index 530e319..7ea777c 100644 (file)
        "talk": "Arutelu",
        "views": "vaatamisi",
        "toolbox": "Tööriistad",
+       "tool-link-userrights": "Muuda {{GENDER:$1|kasutajarühmi}}",
+       "tool-link-emailuser": "Saada {{GENDER:$1|kasutajale}} e-kiri",
        "userpage": "Vaata kasutajalehekülge",
        "projectpage": "Vaata projektilehekülge",
        "imagepage": "Vaata faililehekülge",
        "databaseerror-error": "Tõrge: $1",
        "transaction-duration-limit-exceeded": "Selleks et vältida tiražeerimise suurt mahajäämust, on see tehing katkestatud, kuna kirjutamise kestus ($1) ületas {{PLURAL:$2|$2}} sekundi piirangut.\nKui muudad korraga palju üksusi, siis proovi selle asemel teha mitu väiksemat toimingut.",
        "laggedslavemode": "Hoiatus: Leheküljel võivad puududa viimased uuendused.",
-       "readonly": "Andmebaas on hetkel kirjutuskaitse all",
+       "readonly": "Andmebaas lukustatud",
        "enterlockreason": "Sisesta lukustamise põhjus ning juurdepääsu taastamise ligikaudne aeg",
        "readonlytext": "Andmebaas on praegu lukustatud. Uusi sissekandeid ja muid muudatusi ei saa teha. Tõenäoliselt toimub andmebaasi plaanipärane hooldus, mille järel tavaline olukord taastub.\nSüsteemiadministraator, kes andmebaasi lukustas, andis järgmise selgituse: $1",
        "missing-article": "Andmebaas ei leidnud küsitud lehekülje \"$1\" $2 teksti.\n\nPõhjuseks võib olla võrdlus- või ajaloolink kustutatud leheküljele.\n\nKui tegemist ei ole nimetatud olukorraga, võib tegu olla ka süsteemi veaga.\nSellisel juhul tuleks teavitada [[Special:ListUsers/sysop|administraatorit]], edastades talle ka käesoleva lehe internetiaadressi.",
        "internalerror-fatal-exception": "Saatuslik erandtöötluse tõrge: $1",
        "filecopyerror": "Ei saanud faili \"$1\" kopeerida nimega \"$2\".",
        "filerenameerror": "Ei saanud faili \"$1\" failiks \"$2\" ümber nimetada.",
-       "filedeleteerror": "Faili nimega \"$1\" ei ole võimalik kustutada.",
+       "filedeleteerror": "Faili \"$1\" ei õnnestunud kustutada.",
        "directorycreateerror": "Kataloogi \"$1\" ei saanud luua.",
        "directoryreadonlyerror": "Kataloog \"$1\" on kirjutuskaitstud.",
        "directorynotreadableerror": "Kataloog \"$1\" pole loetav.",
        "myprivateinfoprotected": "Sul pole lubatud oma eraandmeid redigeerida.",
        "mypreferencesprotected": "Sul pole lubatud oma eelistusi muuta.",
        "ns-specialprotected": "Erilehekülgi ei saa redigeerida.",
-       "titleprotected": "Kasutaja [[User:$1|$1]] on selle pealkirjaga lehe loomise keelanud esitades järgmise põhjenduse: <em>$2</em>.",
+       "titleprotected": "Kasutaja [[User:$1|$1]] on selle pealkirjaga lehekülje loomise keelanud, esitades järgmise põhjenduse: <em>$2</em>.",
        "filereadonlyerror": "Faili \"$1\" ei saa muuta, sest hoidla \"$2\" on kirjutuskaitstud.\n\nSüsteemiadministraator lukustas selle järgmisel põhjusel: \"$3\".",
        "invalidtitle-knownnamespace": "Vigane pealkiri nimeruumis \"$2\" tekstiga \"$3\"",
        "invalidtitle-unknownnamespace": "Vigane pealkiri nimeruuminumbriga $1 ja tekstiga \"$2\"",
        "password-change-forbidden": "Selles vikis ei saa paroole muuta.",
        "externaldberror": "Esines autentimistõrge või sul pole õigust konto andmeid muuta.",
        "login": "Sisselogimine",
+       "login-security": "Identsuskontroll",
        "nav-login-createaccount": "Logi sisse või registreeru kasutajaks",
        "userlogin": "Sisselogimine või kasutajakonto loomine",
        "userloginnocreate": "Sisselogimine",
        "userlogin-resetpassword-link": "Kas unustasid parooli?",
        "userlogin-helplink2": "Sisselogimisabi",
        "userlogin-loggedin": "Oled juba sisse logitud nimega {{GENDER:$1|$1}}.\nKasuta allolevat vormi, et logida sisse teise kasutajaga.",
+       "userlogin-reauth": "Pead uuesti sisse logima tõestamaks, et oled {{GENDER:$1|$1}}.",
        "userlogin-createanother": "Loo teine konto",
        "createacct-emailrequired": "E-posti aadress",
        "createacct-emailoptional": "E-posti aadress (valikuline)",
        "resetpass-temp-password": "Ajutine parool:",
        "resetpass-abort-generic": "Tarkvaralisa on paroolimuudatuse abortinud.",
        "resetpass-expired": "Sinu parool on iganenud. Palun määra uus parool, et sisse logida.",
-       "resetpass-expired-soft": "Sinu parool on iganenud ja tuleb uuesti määrata. Palun vali kohe uus parool või klõpsa \"{{int:authprovider-resetpass-skip-label}}\", et määrata see hiljem.",
-       "resetpass-validity-soft": "Sinu parool ei sobi: $1\n\nPalun vali kohe uus parool või klõpsa \"{{int:authprovider-resetpass-skip-label}}\", et see hiljem uuesti määrata.",
+       "resetpass-expired-soft": "Sinu parool on iganenud ja tuleb uuesti määrata. Palun vali kohe uus parool või klõpsa nuppu \"{{int:authprovider-resetpass-skip-label}}\", et määrata see hiljem.",
+       "resetpass-validity-soft": "Sinu parool ei sobi: $1\n\nPalun vali kohe uus parool või klõpsa nuppu \"{{int:authprovider-resetpass-skip-label}}\", et see hiljem uuesti määrata.",
        "passwordreset": "Parooli lähtestamine",
        "passwordreset-text-one": "Täida see vorm, et oma parool lähtestada.",
        "passwordreset-text-many": "{{PLURAL:$1|Täida üks väljadest, et saada e-kiri ajutise parooliga.}}",
        "changecontentmodel-title-label": "Lehekülje pealkiri",
        "changecontentmodel-model-label": "Uus sisumudel",
        "changecontentmodel-reason-label": "Põhjus:",
+       "changecontentmodel-submit": "Muuda",
        "changecontentmodel-success-title": "Sisumudel on muudetud",
        "changecontentmodel-success-text": "Lehekülje [[:$1]] sisumudel on muudetud.",
        "changecontentmodel-cannot-convert": "Lehekülje [[:$1]] sisumudelit ei saa teisendada tüübiks $2.",
        "undeletehistorynoadmin": "See lehekülg on kustutatud.\nKustutamise põhjus ning selle lehekülje kustutamiseelne redigeerimislugu on näha allolevas kokkuvõttes.\nLehekülje kustutamiseelsed redaktsioonid on kättesaadavad ainult administraatoritele.",
        "undelete-revision": "Lehekülje $1 kustutatud redaktsioon, mille autor on $3, seisuga $4, kell $5.",
        "undeleterevision-missing": "Vigane või puuduv redaktsioon.\nLink võib olla kõlbmatu või redaktsioon võib olla taastatud või arhiivist eemaldatud.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|Üht|$1}} redaktsiooni ei saanud taastada, sest {{PLURAL:$1|selle|nende}} <code>rev_id</code> oli juba kasutuses.",
        "undelete-nodiff": "Varasemat redaktsiooni ei leidunud.",
        "undeletebtn": "Taasta",
        "undeletelink": "vaata/taasta",
        "sp-contributions-username": "IP-aadress või kasutajanimi:",
        "sp-contributions-toponly": "Ainult uusimad redaktsioonid",
        "sp-contributions-newonly": "Näita ainult uute lehekülgedega alustamist",
+       "sp-contributions-hideminor": "Peida pisimuudatused",
        "sp-contributions-submit": "Otsi",
        "whatlinkshere": "Lingid siia",
        "whatlinkshere-title": "Leheküljed, mis viitavad lehele \"$1\"",
        "ipb-unblock": "Kasutaja või IP-aadressi vabastamine blokeerimisest",
        "ipb-blocklist": "Vaata kehtivaid blokeeringuid",
        "ipb-blocklist-contribs": "Kasutaja $1 kaastöö",
+       "ipb-blocklist-duration-left": "$1 järel",
        "unblockip": "Blokeerimise eemaldamine",
        "unblockiptext": "Kasuta allpool olevat vormi varem blokeeritud IP-aadressi või kasutaja redigeerimisõiguse taastamiseks.",
        "ipusubmit": "Eemalda see blokeering",
        "block-log-flags-hiddenname": "kasutajanimi peidetud",
        "range_block_disabled": "Administraatori õigus blokeerida IP-aadresside vahemik on ära võetud.",
        "ipb_expiry_invalid": "Vigane aegumise tähtaeg.",
+       "ipb_expiry_old": "Aegumistähtaeg on minevikus.",
        "ipb_expiry_temp": "Peidetud kasutajanime blokeeringud peavad olema alalised.",
        "ipb_hide_invalid": "Seda kontot ei saa varjata, sest sellega on tehtud üle {{PLURAL:$1|ühe|$1}} muudatuse.",
        "ipb_already_blocked": "\"$1\" on juba blokeeritud.",
        "pageinfo-article-id": "Lehekülje identifikaator",
        "pageinfo-language": "Lehekülje sisu keel",
        "pageinfo-content-model": "Lehekülje sisumudel",
+       "pageinfo-content-model-change": "muuda",
        "pageinfo-robot-policy": "Robotindekseering",
        "pageinfo-robot-index": "Lubatud",
        "pageinfo-robot-noindex": "Keelatud",
        "pageinfo-category-files": "Faile",
        "markaspatrolleddiff": "Märgi kontrollituks",
        "markaspatrolledtext": "Märgi see leht kontrollituks",
+       "markaspatrolledtext-file": "Märgi see failiversioon kontrollituks",
        "markedaspatrolled": "Kontrollituks märgitud",
        "markedaspatrolledtext": "Valitud redaktsioon leheküljel [[:$1]] on kontrollituks märgitud.",
        "rcpatroldisabled": "Viimaste muudatuste kontroll ei toimi",
        "confirm-watch-top": "Kas lisad selle lehekülje oma jälgimisloendisse?",
        "confirm-unwatch-button": "Sobib",
        "confirm-unwatch-top": "Kas eemaldad selle lehekülje oma jälgimisloendist?",
+       "confirm-rollback-button": "Sobib",
        "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← eelmine lehekülg",
        "imgmultipagenext": "järgmine lehekülg →",
        "feedback-thanks": "Aitäh! Sinu tagasiside on postitatud leheküljele \"[$2 $1]\".",
        "feedback-thanks-title": "Aitäh!",
        "feedback-useragent": "Kasutajaagent:",
-       "searchsuggest-search": "Otsi",
+       "searchsuggest-search": "Otsi {{GRAMMAR:elative|{{SITENAME}}}}",
        "searchsuggest-containing": "sisalduv...",
        "api-error-badaccess-groups": "Sul pole selles vikis üleslaadimisõigust.",
        "api-error-badtoken": "Sisemine tõrge: Sobimatu nimi.",
        "mw-widgets-titleinput-description-new-page": "lehekülge pole veel",
        "mw-widgets-titleinput-description-redirect": "ümbersuunamine leheküljele \"$1\"",
        "randomrootpage": "Juhuslik juurlehekülg",
-       "userjsispublic": "Pea silmas, et JavaScripti alamleheküljed ei tohiks sisaldada konfidentsiaalseid andmeid, kuna neid näevad teised kasutajad."
+       "authmanager-provider-password": "Paroolipõhine autentimine",
+       "authmanager-provider-password-domain": "Parooli- ja domeenipõhine autentimine",
+       "authmanager-provider-temporarypassword": "Ajutine parool",
+       "changecredentials": "Autentimisandmete muutmine",
+       "changecredentials-submit": "Muuda autentimisandmed",
+       "changecredentials-success": "Sinu autentimisandmed on muudetud.",
+       "removecredentials": "Autentimisandmete eemaldamine",
+       "removecredentials-submit": "Eemalda autentimisandmed",
+       "removecredentials-success": "Sinu autentimisandmed on eemaldatud.",
+       "credentialsform-provider": "Andmete tüüp:",
+       "credentialsform-account": "Konto nimi:",
+       "userjsispublic": "Pea silmas, et JavaScripti alamleheküljed ei tohiks sisaldada konfidentsiaalseid andmeid, kuna neid näevad teised kasutajad.",
+       "restrictionsfield-badip": "Vigane IP-aadress või -aadressivahemik: $1",
+       "restrictionsfield-label": "Lubatud IP-aadressivahemikud:",
+       "restrictionsfield-help": "Üks IP-aadress või CIDR-vahemik rea kohta. Et lubada kõik, kasuta süntaksit <br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Tõrge: $1",
+       "edit-error-long": "Tõrked:\n\n$1"
 }
index e2feef4..c435b73 100644 (file)
        "blocklist-userblocks": "پنهان کردن بسته‌شدن‌های حساب",
        "blocklist-tempblocks": "پنهان کردن بستن‌های موقت",
        "blocklist-addressblocks": "پنهان کردن تک آی‌پی‌های بسته شده",
-       "blocklist-rangeblocks": "پنهان کردنی قطع دسترسی بازه‌ها",
+       "blocklist-rangeblocks": "پنهان کردن قطع دسترسی بازه‌ها",
        "blocklist-timestamp": "برچسب زمان",
        "blocklist-target": "هدف",
        "blocklist-expiry": "زمان سرآمدن",
index 9720a86..00d06e0 100644 (file)
        "unlinkaccounts-success": "Tunnuksen linkitys poistettiin.",
        "authenticationdatachange-ignored": "Varmennustietojen muutosta ei käsitelty. Ehkä palveluntarjoajaa ei määritelty?",
        "restrictionsfield-badip": "Virheellinen IP-osoite tai alue: $1",
-       "restrictionsfield-label": "Sallitut IP-alueet:"
+       "restrictionsfield-label": "Sallitut IP-alueet:",
+       "edit-error-short": "$1",
+       "edit-error-long": "Virheet:\n\n$1"
 }
index 88b0b5f..e724e2f 100644 (file)
        "movelogpagetext": "Voici la liste de toutes les pages renommées ou déplacées.",
        "movesubpage": "Sous-page{{PLURAL:$1||s}}",
        "movesubpagetext": "Cette page a $1 {{PLURAL:$1|sous-page affichée|sous-pages affichées}} ci-dessous.",
+       "movesubpagetalktext": "La page de discussion correspodnante a $1 {{PLURAL:$1|sous-page|sous-pages}} affichées ci-dessous.",
        "movenosubpage": "Cette page n'a aucune sous-page.",
        "movereason": "Motif :",
        "revertmove": "rétablir",
        "feedback-thanks": "Merci ! Votre commentaire a été publié sur la page « [$2 $1] ».",
        "feedback-thanks-title": "Merci !",
        "feedback-useragent": "Agent utilisateur :",
-       "searchsuggest-search": "Rechercher",
+       "searchsuggest-search": "Rechercher sur {{SITENAME}}",
        "searchsuggest-containing": "contenant...",
        "api-error-autoblocked": "Votre adresse IP a été bloquée automatiquement, parce qu’elle a été utilisée par un utilisateur bloqué.",
        "api-error-badaccess-groups": "Vous n'êtes pas autorisé à verser des fichiers sur ce wiki.",
        "usercssispublic": "Veuillez noter: les sous-pages CSS ne doivent pas contenir de données confidentielles parce qu'elles sont visibles des autres utilisateurs.",
        "restrictionsfield-badip": "Adresse IP ou plage non valide : $1",
        "restrictionsfield-label": "Plages IP autorisées :",
-       "restrictionsfield-help": "Une adresse IP ou une plage CIDR par ligne. Pour tout activer, utiliser <br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "Une adresse IP ou une plage CIDR par ligne. Pour tout activer, utiliser <br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Erreur : $1",
+       "edit-error-long": "Erreurs :\n\n$1"
 }
index 4724ab1..2df46b4 100644 (file)
        "movelogpagetext": "A continuación móstrase a lista con todas as páxinas trasladadas.",
        "movesubpage": "{{PLURAL:$1|Subpáxina|Subpáxinas}}",
        "movesubpagetext": "Esta páxina ten $1 {{PLURAL:$1|subpáxina|subpáxinas}}.",
+       "movesubpagetalktext": "A páxina de conversa correspondente ten $1 {{PLURAL:$1|subpáxina|subpáxinas}} mostradas abaixo.",
        "movenosubpage": "Esta páxina non ten subpáxinas.",
        "movereason": "Motivo:",
        "revertmove": "reverter",
        "feedback-thanks": "Grazas! Os seus comentarios publicáronse na páxina \"[$2 $1]\".",
        "feedback-thanks-title": "Grazas!",
        "feedback-useragent": "Axente de usuario:",
-       "searchsuggest-search": "Procurar",
+       "searchsuggest-search": "Procurar en {{SITENAME}}",
        "searchsuggest-containing": "que conteña...",
        "api-error-autoblocked": "A súa dirección IP foi bloqueada automaticamente porque foi usada por un usuario bloqueado.",
        "api-error-badaccess-groups": "Non ten os permisos necesarios para cargar ficheiros neste wiki.",
        "usercssispublic": "Lembre: As subpáxinas CSS non deberían conter datos confidenciais porque outros usuarios poden velos.",
        "restrictionsfield-badip": "Enderezo IP ou rango de IP non válido: $1",
        "restrictionsfield-label": "Rangos de IP permitidos:",
-       "restrictionsfield-help": "Un único enderezo IP ou rango CIDR por liña. Para habilitalos todos, utilice<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "Un único enderezo IP ou rango CIDR por liña. Para habilitalos todos, utilice<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Erro: $1",
+       "edit-error-long": "Erros:\n\n$1"
 }
index f1cf530..edd2fc9 100644 (file)
@@ -24,7 +24,7 @@
        "tog-newpageshidepatrolled": "Yún-chhông sîn ya̍p-mien chhîn-tân tú sùn-chhà ko ke ya̍p-mien",
        "tog-extendwatchlist": "Chán-khôi kâm-sṳ lie̍t-péu lòi hién-sṳ só-yû kiên-kói, m̀  tân-chhiang he chui-khiûn ke",
        "tog-usenewrc": "Chhai chui-khiûn kiên-kói lâu kâm-sṳ lie̍t-péu tú cháng-ha̍p thùng yit-ya̍p ke siû-kói",
-       "tog-numberheadings": "Phiêu-thì chhṳ-thûng phiên-ho",
+       "tog-numberheadings": "Phiêu-thì chhṳ-thung phiên-ho",
        "tog-showtoolbar": "Chán-sṳ phiên-siá kûng-khí-làn",
        "tog-editondblclick": "Sûng-khim phiên-siá ya̍p-mien",
        "tog-editsectiononrightclick": "Yún-hí yu-khim phiêu-thì phiên-siá thon-lo̍k",
        "october-date": "10-ngie̍t $1-ngit",
        "november-date": "11-ngie̍t $1-ngit",
        "december-date": "12-ngie̍t $1-ngit",
-       "pagecategories": "{{PLURAL:$1|Category|$1-chak fûn-lui}}",
+       "pagecategories": "{{PLURAL:$1|Fûn-lui}}",
        "category_header": "\"$1\" fûn-lui tú ke ya̍p-mien",
        "subcategories": "Chṳ́ fûn-lui",
        "category-media-header": "\"$1\" fûn-lui tú ke mòi-thí",
        "viewsource-title": "Khon $1 ke ngièn-sṳ́-mâ",
        "actionthrottled": "動作已經壓制",
        "actionthrottledtext": "基於反垃圾嘅考量,短時間內毋可以多次重複某操作,今下汝已經超過邇隻上限。\n請在數分鐘後再嘗試。",
-       "protectedpagetext": "邇隻頁面已經分人保護以防止編輯或其他操作。",
-       "viewsourcetext": "汝做得查看並複製本頁面嘅源碼:",
+       "protectedpagetext": "Liá ya̍p yí-kîn pûn ngìn pó-fu, kim-chṳ́ siû-kói fe̍t-chá khì-thâ chhâu-chok.",
+       "viewsourcetext": "Ngì cho-tet khon fe̍t-chá copy liá ya̍p ke ngièn-sṳ́-mâ:",
        "viewyourtext": "汝可以查看並複製'''汝對邇隻頁面作出編寫後'''嘅源代碼:",
        "protectedinterface": "邇頁提供此wiki軟體嘅介面文字,其已畀保護以防止惡意修改。\n假使想修改所有wiki嘅翻譯,請到[https://translatewiki.net/ translatewiki.net]上嘅MediaWiki本地化計畫。",
        "editinginterface": "'''警告:'''汝今下編寫緊嘅頁面係用於提供軟件嘅界面文字。\n改變邇頁將影響其他在邇隻wiki上嘅用戶界面外觀。\n假使愛修改所有wiki嘅翻譯,請到[https://translatewiki.net/ translatewiki.net]上嘅MediaWiki本地化計劃。",
        "yourpasswordagain": "Chai yit-pái sû-ngi̍p me̍t-ma:",
        "createacct-yourpasswordagain": "Khok-ngin me̍t-ma",
        "createacct-yourpasswordagain-ph": "Chai yit-pái sû-ngi̍p me̍t-ma",
-       "remembermypassword": "Chhai liá-chak liù-lám-hi sông ki-hâ ngài-ke tên-ngi̍p chhong-thai (chui-chhòng $1-ngit)",
        "userlogin-remembermypassword": "Pó-chhṳ̀ ngài-ke tên-ngi̍p chhong-thai",
        "userlogin-signwithsecure": "使用安全連線",
        "yourdomainname": "Ngì ke vet-miàng:",
        "password-change-forbidden": "汝做毋得更改本wiki上嘅密碼。",
-       "externaldberror": "Liá khó-nèn he yù-yî ngiam-chṳn sú-kí-khù chhâ-chho fe̍t-chá ngì fûn hì-thúng kim-chṳ́ kiên-sîn ngì ke ngoi-phu chòng-ho.",
+       "externaldberror": "Liá khó-nèn he yù-yî ngiam-chṳn sú-kí-khù chhâ-chho fe̍t-chá ngì fûn hì-thúng kim-chṳ́ kiên-sîn ngì ke ngoi-phu fu-thèu.",
        "login": "Tên-ngi̍p",
-       "nav-login-createaccount": "Tên-ngi̍p / kien-li̍p sîn chong-ho",
-       "userlogin": "Tên-ngi̍p / kien-li̍p sîn chong-ho",
+       "nav-login-createaccount": "Tên-ngi̍p / khôi sîn fu-thèu",
+       "userlogin": "Tên-ngi̍p / khôi sîn fu-thèu",
        "userloginnocreate": "Tên-ngi̍p",
        "logout": "Tên-chhut",
        "userlogout": "Tên-chhut",
        "notloggedin": "Hàn-mò tên-ngi̍p",
-       "userlogin-noaccount": "Hàn-mò chong-fu he mò?",
+       "userlogin-noaccount": "Hàn-mò fu-thèu he mò?",
        "userlogin-joinproject": "Chhâm-yi  {{SITENAME}}",
-       "nologin": "Hàn-mò chong-ho he-mò? $1.",
-       "nologinlink": "Kien-li̍p chong-ho",
-       "createaccount": "Kien-li̍p chong-ho",
-       "gotaccount": "Yí-kîn yúng-yû chong-ho he-mò? $1.",
+       "nologin": "Hàn-mò fu-thèu he-mò? $1.",
+       "nologinlink": "Khôi fu-thèu",
+       "createaccount": "Khôi fu-thèu",
+       "gotaccount": "Yí-kîn yû fu-thèu he-mò? $1.",
        "gotaccountlink": "Tên-ngi̍p",
        "userlogin-resetlink": "M̀-ki-tet ngì-ke tên-ngi̍p sin-sit?",
        "userlogin-resetpassword-link": "Thiâm mong-ki ngì ke me̍t-ma?",
        "createaccountreason": "Ngièn-yîn:",
        "createacct-reason": "Ngièn-yîn:",
        "createacct-reason-ph": "汝做麽嘅愛創建另一隻帳號",
-       "createacct-submit": "Kien-li̍p chong-ho",
+       "createacct-submit": "Khôi fu-thèu",
        "createacct-benefit-heading": "{{SITENAME}} he yù lâu Ngì khiung-ngióng ke ngìn kien-li̍p.",
        "createacct-benefit-body1": "$1-chhṳ phiên-siá",
        "createacct-benefit-body2": "$1-ya̍p",
        "badretype": "Ngì só khim-ngi̍p ke me̍t-ma pin m̀  siông-thùng.",
        "userexists": "汝所填入嘅用戶名稱已經存在。\n請另選一隻名稱。",
        "loginerror": "Tên-ngi̍p chhâ-chho",
-       "createacct-error": "Chong-fu kien-li̍p chhâ-chho",
-       "createaccounterror": "Mò phan-fap kien-li̍p chong-ho: $1",
+       "createacct-error": "Khôi fu-thèu chhut chhâ-chho",
+       "createaccounterror": "Mò-fap-thu khôi sîn fu-thèu: $1",
        "nocookiesnew": "本用戶賬號已分建立,但係汝登入失敗。{{SITENAME}}使用cookie登入。汝已停用cookie。請啓用cookie,之後使用汝嘅新用戶名和密碼登入。",
        "nocookieslogin": "{{SITENAME}}用cookie登入。汝已停用cookie。請啓用cookie後再試一擺。",
        "nocookiesfornew": "邇隻用戶嘅賬戶未建立,亻厓兜無法度確認其嘅來源。\n請確定汝已經開啟cookies,重新載入後再試一擺。",
        "noname": "汝還吂輸入一隻有效嘅用戶名。",
        "loginsuccesstitle": "Yí-kîn tên-ngi̍p",
        "loginsuccess": "Ngì kîm-hâ yî \"$1\"-ke sṳ̂n-fun chhai {{SITENAME}} tên-ngi̍p.",
-       "nosuchuser": "Chhìm m̀ -to yung-fu \"$1\". \nYung-fu miàng-chhṳ̂n he yû thai-séu siá khî-fûn ke . \nKiám-chhà ngì ke piâng-siá, fe̍t-chá yung hâ-mien ke péu-kak [[Special:CreateAccount|kien-li̍p yit-chak sîn chòng-ho]].",
+       "nosuchuser": "Chhìm m̀ -to yung-fu \"$1\". \nYung-fu miàng-chhṳ̂n he yû thai-séu siá khî-fûn ke . \nKiám-chhà ngì ke piâng-siá, fe̍t-chá yung hâ-mien ke péu-kak [[Special:CreateAccount|khôi yit-chak sîn fu-thèu]].",
        "nosuchusershort": "無有喊做“$1”嘅用戶。請檢查汝輸入嘅文字係毋係有差錯。",
        "nouserspecified": "汝愛指定一隻用戶名。",
        "login-userblocked": "邇隻用戶已分封鎖。毋做得登入。",
        "suspicious-userlogout": "汝登出嘅要求已經分拒絕,因為其可能係由已損壞嘅瀏覽器或者緩存代理傳送。",
        "pt-login": "Tên-ngi̍p",
        "pt-login-button": "Tên-ngi̍p",
-       "pt-createaccount": "Kien-li̍p chong-ho",
+       "pt-createaccount": "Khôi fu-thèu",
        "pt-userlogout": "Tên-chhut",
        "php-mail-error-unknown": "在PHP嘅mail()參數肚嘅未知錯誤",
        "user-mail-no-addy": "嘗試毋帶電郵地址發送電郵。",
        "preview": "預覽",
        "showpreview": "Chán-sṳ yi-lám",
        "showdiff": "Chán-sṳ chhâ-phe̍t",
-       "anoneditwarning": "<strong>Kín-ko : </strong>Ngì hàn-m̀ tên-ngi̍p. Ngì ke IP thi-chí chiông ki-liu̍k chhai liá-ya̍p ke phiên-siá li̍t-sṳ́ tú. Ká-sṳ́ ngì  <strong>[$1 tên-ngi̍p]</strong> fe̍t  <strong>[$2 kien-li̍p chong-ho]</strong>, ngì ke phiên-si̍p chiông-fi yî ngì ke sṳ́-yung-chá miàng-chhṳ̂n phiêu-sṳ, yúng-yû khì-thâ yù-tiám.",
+       "anoneditwarning": "<strong>Kín-ko:</strong> Ngì hàn-m̀ tên-ngi̍p. Ngì ke IP vi-chí voi ki-liu̍k chhai liá ya̍p ke phiên-siá li̍t-sṳ́ tú. Na-he ngì <strong>[$1 tên-ngi̍p]</strong> fe̍t-chá <strong>[$2 khôi fu-thèu]</strong>, ngì ke phiên-siá voi hién-sṳ ngì ke yung-fu miàng-sṳ, pin-chhiâ yû khì-thâ ke yù-tiám.",
        "anonpreviewwarning": "“警告:汝還吂登入。汝嘅IP地址將會記錄在邇頁嘅編輯歷史中”",
        "missingsummary": "'''提示:''' 汝無提供一隻編寫摘要。假使汝再次單擊「{{int:savearticle}}」,汝嘅編寫將毋帶編寫摘要保存。",
        "missingcommenttext": "請在下背輸入評論。",
        "subject-preview": "主題/標題預覽:",
        "blockedtitle": "用戶分查封",
        "blockedtext": "Ngì-ke yung-fu-miàng fe̍t-chá IP thi-tiám yí-kîn pûn $1 chhà-fûng.\n\nLiá-chhṳ chhà-fûng he yù $1 só fûng ke. Tông-chûng ke ngièn-yîn he ''$2''. Ngì khó-yî lièn-lo̍k $1 fe̍t-chá khì-thâ ke [[{{MediaWiki:Grouppage-sysop}}|Kón-lî-yèn]], thó-lun liá-chhṳ ke chhà-fûng. Chhù-fî ngì yí-kîn chhai ngì-ke [[Special:Preferences|Chong-ho chhâm-su sat-chṳ]] chûng sat-thin liáu yit-ke yû-háu ke email, féu-chet ngì-he put-nèn sṳ́-yung “email liá-vi yung-fu” ke kûng-yung. Ngì-ke IP thi-tiám he $3, yì-yèn ke chhà-fûng ID he #$5. Chhiáng ngì chhai só-yû chhà-chhìm chûng chu-mìn liá-ke thi-tiám khi̍p/fe̍t-he chhà-fûng ID.",
-       "autoblockedtext": "Ngì-ke IP thi-tiám yí-kîn pûn chhṳ-thung chhà-fûng, lî-yù he siên-chhièn ke nang yit-vi yung-fu pûn $1 só chhà-fûng. Yì-yèn chhà-fûng ke ngièn-yîn he: ''$2'' liá-chhṳ chhà-fûng ke khì-kiên he: $6 ngì khó-yî lièn-lo̍k $1 fe̍t-chá khì-thâ ke [[{{MediaWiki:Grouppage-sysop}}|kón-lî-yèn]], thó-lun liá-chhṳ chhà-fûng. Chhù-fî ngì yí-kîn chhai ngì-ke [[Special:Preferences|chong-ho chhâm-su sat-chṳ]] chûng sat-thin yit-ke yû-háu ke email thi-tiám, féu-chet ngì-he put-nèn sṳ́-yung \"email liá-vi yung-fu\" ke kûng-nèn. Ngì-ke chhà-fûng ID he $5. Chhiáng ngì chhai só-yû thiàu-chhà chûng chu-mìn liá-ke chhà-fûng ID.",
+       "autoblockedtext": "Ngì-ke IP thi-tiám yí-kîn pûn chhṳ-thung chhà-fûng, lî-yù he siên-chhièn ke nang yit-vi yung-fu pûn $1 só chhà-fûng. Yì-yèn chhà-fûng ke ngièn-yîn he: ''$2'' liá-chhṳ chhà-fûng ke khì-kiên he: $6 ngì khó-yî lièn-lo̍k $1 fe̍t-chá khì-thâ ke [[{{MediaWiki:Grouppage-sysop}}|kón-lî-yèn]], thó-lun liá-chhṳ chhà-fûng. Chhù-fî ngì yí-kîn chhai ngì-ke [[Special:Preferences|fu-thèu chhâm-su sat-chṳ]] chûng sat-thin yit-ke yû-háu ke email thi-tiám, féu-chet ngì-he put-nèn sṳ́-yung \"email liá-vi yung-fu\" ke kûng-nèn. Ngì-ke chhà-fûng ID he $5. Chhiáng ngì chhai só-yû thiàu-chhà chûng chu-mìn liá-ke chhà-fûng ID.",
        "whitelistedittext": "汝必須先$1正做得編寫頁面。",
        "confirmedittext": "在編寫邇頁之前汝必須確認汝嘅郵箱地址。請通過[[Special:Preferences|偏好設定]]設定並驗證汝嘅郵箱地址。",
        "nosuchsectiontitle": "Mò-yû liá-ke thon-lo̍k",
        "nocreate-loggedin": "汝並無權限去創建新頁面。",
        "permissionserrors": "Khièn-han chhâ-chho",
        "permissionserrorstext": "Kîn-kí yî-ha ke ngièn-yîn, ngì vù-yû khièn-han hi-tso yî-ha ke thung-tsok:",
-       "permissionserrorstext-withaction": "根據下背嘅{{PLURAL:$1|原因|原因}},汝並無權限去做$2:",
+       "permissionserrorstext-withaction": "Yîn-vi hâ-poi ke {{PLURAL:$1|ngièn-yîn}}, ngì mò-fap-thu $2:",
        "recreate-moveddeleted-warn": "'''警告:汝今下重新建立一隻先前曾經刪除過嘅頁面。'''\n\n汝應該愛考慮一下繼續編寫邇一隻頁面係毋係合適。\n為到方便,邇一個頁面嘅刪除日誌已經在下背提供:",
        "moveddeleted-notice": "Liá-chak ya̍p-mien yí-kîn san-chhù. \nLiá-chak ya̍p-mien ke san-chhù lâu yì-thûng ngit-chì yí-kîn chhai hâ-poi thì-kiûng lòi chhâm-kháu.",
        "log-fulllog": "Chhà-khon vàn-cháng ngit-chì",
        "undo-failure": "由於中途嘅編寫毋一致,本編輯毋做得撤銷。",
        "undo-norev": "由於其嘅修訂版本毋存在或已刪除,本編寫毋做得撤銷。",
        "undo-summary": "Chhí-sêu yù [[Special:Contributions/$2|$2]] ([[User talk:$2|tui-fa]]) só chok-chhut ke siû-thin $1",
-       "cantcreateaccounttitle": "Mò-fap kien-li̍p chong-ho",
        "cantcreateaccount-text": "從邇隻IP地址('''$1''')建立帳號已經分[[User:$3|$3]]禁止。\n\n當中分$3封禁嘅原因是''$2''",
        "viewpagelogs": "Chhà-khon liá-chak ya̍p-mien ke ngit-chì",
        "nohistory": "無本頁嘅修訂版本記錄。",
        "previousrevision": "← Sông-chak pán-pún",
        "nextrevision": "Hâ-chak pán-pún →",
        "currentrevisionlink": "Chui-sîn pán-pún",
-       "cur": "tông-chhièn",
-       "next": "下一隻",
-       "last": "sông yit-chak",
+       "cur": "kîm",
+       "next": "Heu",
+       "last": "chhièn",
        "page_first": "chui-chó",
        "page_last": "chui-mî",
-       "histlegend": "差別選擇:標記愛比較版本嘅單選按鈕並點擊底部嘅按鈕進行比較。<br />\n說明:'''({{int:cur}})''' 指撈最新版本比較,'''({{int:last}})''' 指撈上隻版本比較,'''{{int:minoreditletter}}''' = 細微修改。",
+       "histlegend": "Chhâ-phe̍t sién-chet: pêu-ki oi pí-káu pán-pún, tiám hâ-poi ke \"Pí-káu sién-chet ke pán-pún\" yung lòi pí-káu.<br />\nSot-mìn: <strong>({{int:cur}})</strong> chṳ́ lâu chui sîn pán-pún pí-káu, <strong>({{int:last}})</strong> chṳ́ thùng chhièn yit ke pán-pún pí-káu, <strong>{{int:minoreditletter}}</strong> = se-mì siû-kói.",
        "history-fieldset-title": "Liù-lám li̍t-sṳ́",
        "history-show-deleted": "Tân-chhiang he yí san-chhù ke",
        "histfirst": "chui-chó",
        "history-title": "\"$1\" ke siû-thin li̍t-sṳ́",
        "difference-title": "\"$1\" siû-thin kiên ke chhâ-bie",
        "lineno": "Thi $1 hàng:",
-       "compareselectedversions": "比較選定嘅修訂版本",
-       "editundo": "Chha̍t-siau",
+       "compareselectedversions": "Pí-káu sién-chet ke pán-pún",
+       "editundo": "Chhí-sêu",
        "searchresults": "Sêu-chhìm kiet-kó",
        "searchresults-title": "Sêu -chhìm \"$1\" ke kiet-kó",
        "titlematches": "頁面標題相符",
        "deletereasonotherlist": "其它理由",
        "rollback": "編寫倒轉頭",
        "rollbacklink": "tá chón-thèu",
-       "rollbacklinkcount": "chha̍t-siau $1 chhṳ phiên-siá",
+       "rollbacklinkcount": "chhí-sêu $1 chhṳ phiên-siá",
        "rollbackfailed": "無法倒轉頭",
        "cantrollback": "編寫無法打轉頭;最後嘅貢獻者人本文嘅唯一作者。",
        "alreadyrolled": "Mò-fap fî-fu̍k yù [[User:$2|$2]] ([[User talk:$2|thó-lun]]) chin-hàng ke [[$1]] ke chui-heu phiên-si̍p; khì-thâ ngìn yí-kîn phiên-siá fe̍t-he fî-fu̍k liáu ke-hong. Chui-heu phiên-si̍p-chá: [[User:$3|$3]] ([[User talk:$3|Thó-lun]])。",
        "sessionfailure": "汝嘅登入會話好像有問題;\n為到防止會話劫持,邇次操作已經畀取消。\n請轉到先前嘅頁面,重新載入邇頁面,然後重試。",
        "protectlogpage": "Pó-fu ngit-chì",
        "protectlogtext": "Ha-mien he vùn-chông só-thin lâu chhí-sêu só-thin ke lie̍t-péu. Chhiáng chhâm-kháu [[Special:ProtectedPages|Pó-fu vùn-chông chhîn-tân]] yî-khi̍p kiám-sṳ tông-chhièn chin-hàng ke vùn-chông pó-fu.",
-       "protectedarticle": "已保護“[[$1]]”",
+       "protectedarticle": "yí-kîn pó-fu \"[[$1]]\"",
        "modifiedarticleprotection": "已經更改“[[$1]]”嘅保護等級",
        "unprotectedarticle": "yí-kîn kié-chhù pó-fu \"[[$1]]\"",
        "protect-title": "更改“$1”嘅保護等級",
        "ipaddressorusername": "IP thi-chí fe̍t yung-fu-miàng:",
        "ipbexpiry": "Khì-han:",
        "ipbreason": "Ngièn-yîn:",
-       "ipbreason-dropdown": "*Yit-pân ke fûng-kim lî-yù \n** Tô-chhṳ kâ-ngi̍p hî-ká chṳ̂-liau \n** San-chhù ya̍p-mien nui-yùng \n** Ngoi-phu lièn-chiap kóng-ko \n** Chhai ya̍p-mien tú chen-kâ mò yi-ngi vùn-sṳ \n** Mò-lî ke hàng-vì, kûng-kit / sâu-yéu phe̍t-sâ \n** Làm-yung tô-chak chòng-ho \n** Cho-m̀ tet chiap-su ke yung-fu-miàng",
-       "ipbcreateaccount": "Chú-chṳ́ chhóng-kien sîn chòng-ho",
+       "ipbreason-dropdown": "*Yit-pân ke fûng-kim lî-yù \n** Tô-chhṳ kâ-ngi̍p hî-ká chṳ̂-liau \n** San-chhù ya̍p-mien nui-yùng \n** Ngoi-phu lièn-chiap kóng-ko \n** Chhai ya̍p-mien tú chen-kâ mò yi-ngi vùn-sṳ \n** Mò-lî ke hàng-vì, kûng-kit / sâu-yéu phe̍t-sâ \n** Làm-yung tô-chak fu-thèu \n** Cho-m̀ tet chiap-su ke yung-fu-miàng",
+       "ipbcreateaccount": "Chú-chṳ́ kien-li̍p sîn fu-thèu",
        "ipbenableautoblock": "Chhṳ-thûng chhà-fûng liá yung-fu chui-heu só yung ke IP thi-chí, lâu heu-lòi sṳ-thù phiên-siá só yung ke só-yû thi-chí",
        "ipbsubmit": "Chhà-fûng liá yung-fu",
        "ipbother": "其它時間:",
        "tooltip-pt-userpage": "{{GENDER:|Ngì ke sṳ́-yung-chá}} ya̍p-mien",
        "tooltip-pt-anonuserpage": "Ngì-ke phiên-siá pún-chham só yung IP ke tui-yin yung-fu-chông",
        "tooltip-pt-mytalk": "{{GENDER:|Ngì ke}} kâu-liù ya̍p",
-       "tooltip-pt-anontalk": "Tui-yî lòi-chhṳ chhṳ́IP thi-tiám phiên-siá ke tui-fa",
+       "tooltip-pt-anontalk": "Liá ke IP vi-chṳ́ yû-koân phiên-siá ke thó-lun",
        "tooltip-pt-preferences": "{{GENDER:|Ngì ke}} phiên-hó sat-thin",
        "tooltip-pt-watchlist": "Ngì kâm-sṳ chûng ya̍p-mien ke kiên-kói lie̍t-péu",
        "tooltip-pt-mycontris": "{{GENDER:|Ngì ke}} kung-hien lie̍t-péu",
-       "tooltip-pt-login": "Kien-ngi ngì tên-ngi̍p, than-he pin fî pit-sî ke",
+       "tooltip-pt-login": "Kien-ngi ngì tên-ngi̍p, m̀-ko mò-yit-thin oi.",
        "tooltip-pt-logout": "Tên-chhut",
+       "tooltip-pt-createaccount": "Kien-ngi ngì siên khôi yit ke fu-thèu chai tên-ngi̍p; m̀-ko mò-yit-thin oi.",
        "tooltip-ca-talk": "Liá ya̍p ke thó-lun",
        "tooltip-ca-edit": "Phiên-siá pún-ya̍p",
        "tooltip-ca-addsection": "Khôi-sṳ́ yit-chak sîn thon-lo̍k",
        "confirmemail_success": "Ngì-ke sin-siông yí-kîn pûn khok-ngin. Ngì hien-ha khó-yî tên-liu̍k pin sṳ́-yung chhṳ́ mióng-chham liáu.",
        "confirmemail_loggedin": "Ngì-ke sin-siông thi-tiám hien-ha yí-kîn pûn khok-ngin.",
        "confirmemail_subject": "{{SITENAME}} sin-siông thi-tiám khok-ngin",
-       "confirmemail_body": "Yúng-yû IP thi-tiám $1 ke yung-fu (khó-nèn he ngì) chhai {{SITENAME}} chhóng-chho liáu chong-fu  \"$2\", pin thì-kâu liáu ngì-ke email sin-siông thi-tiám.\n\nChhiáng khok-ngin liá-ke chong-fu  he su̍k-yî ngì-ke, pin thùng-sṳ̀ khí-yung chhai {{SITENAME}} sông ke email sin-siông kûng-nèn. Chhiáng chhai hi-khí chûng tá-khôi ha-mien ke lièn-kiet: $3\n\nKó-yèn ngì *mò-yû* thì-chhut liá-ke chhiáng-khiù,  chhiáng put-yeu tiám-kit Chhṳ́ lièn-kiet. Khok-ngin me̍t-me̍t chiông-voi chhai $4 ko-khì.",
+       "confirmemail_body": "Yúng-yû IP thi-tiám $1 ke yung-fu (khó-nèn he ngì) chhai {{SITENAME}} chhóng-chho liáu fu-thèu  \"$2\", pin thì-kâu liáu ngì-ke email sin-siông thi-tiám.\n\nChhiáng khok-ngin liá-ke fu-thèu  he su̍k-yî ngì-ke, pin thùng-sṳ̀ khí-yung chhai {{SITENAME}} sông ke email sin-siông kûng-nèn. Chhiáng chhai hi-khí chûng tá-khôi ha-mien ke lièn-kiet: $3\n\nKó-yèn ngì *mò-yû* thì-chhut liá-ke chhiáng-khiù,  chhiáng put-yeu tiám-kit Chhṳ́ lièn-kiet. Khok-ngin me̍t-me̍t chiông-voi chhai $4 ko-khì.",
        "scarytranscludedisabled": "[Khiam-wiki chón-von me̍t-me̍t put hí-khó yung]",
        "scarytranscludefailed": "[Tui-put-hí, mù-pán $1 thu̍k-chhí sṳt-phai]",
        "scarytranscludetoolong": "[Tui-put-hí; URL thi-tiám thai-chhòng]",
        "revdelete-restricted": "yí-kîn yin-yung han-tsṳ tsṳ tshâu-tsok-yèn",
        "revdelete-unrestricted": "yí-kîn yì-tshù yû-kûan tshâu-tsok-yè ke han-tsṳ",
        "logentry-move-move": "$1 {{GENDER:$2|yí-kîn yì-thûng}} ya̍p-mien $3 to $4",
-       "logentry-newusers-create": "Yí-kîn {{GENDER:$2|kien-li̍p}} sṳ́-yung-chá chong-ho  $1",
+       "logentry-newusers-create": "Yí-kîn {{GENDER:$2|khôi}} yung-fu fu-thèu $1",
        "logentry-upload-upload": "$1 {{GENDER:$2|yí-kîn sông-chhòn}} $3",
        "rightsnone": "(無)",
        "revdelete-summary": "piên-sip tsak-yêu",
index e1b5118..0d1e3c7 100644 (file)
        "deletethispage": "מחיקת דף זה",
        "undeletethispage": "שחזור דף זה",
        "undelete_short": "שחזור {{PLURAL:$1|עריכה אחת|$1 עריכות}}",
-       "viewdeleted_short": "×\94צ×\92ת {{PLURAL:$1|ער×\99×\9b×\94 ×\9e×\97×\95ק×\94 ×\90×\97ת|$1 ×¢×¨×\99×\9b×\94 מחוקות}}",
+       "viewdeleted_short": "×\94צ×\92ת {{PLURAL:$1|ער×\99×\9b×\94 ×\9e×\97×\95ק×\94 ×\90×\97ת|$1 ×¢×¨×\99×\9b×\95ת מחוקות}}",
        "protect": "הגנה",
        "protect_change": "שינוי",
        "protectthispage": "הפעלת הגנה על דף זה",
        "movelogpagetext": "להלן רשימה של כל הדפים ששמם שוּנה.",
        "movesubpage": "{{PLURAL:$1|דף משנה|דפי משנה}}",
        "movesubpagetext": "לדף זה יש {{PLURAL:$1|דף משנה אחד המוצג להלן|$1 דפי משנה המוצגים להלן}}.",
+       "movesubpagetalktext": "לדף השיחה של דף זה יש {{PLURAL:$1|דף משנה אחד המוצג להלן|$1 דפי משנה המוצגים להלן}}.",
        "movenosubpage": "לדף זה אין דפי משנה.",
        "movereason": "סיבה:",
        "revertmove": "החזרה",
        "usercssispublic": "שימו לב: משתמשים אחרים יכולים לצפות בדפי ה־CSS שלכם, ולכן אין לכלול בהם מידע סודי.",
        "restrictionsfield-badip": "כתובת או טווח כתובות IP בלתי תקין: $1",
        "restrictionsfield-label": "טווחי כתובות IP מותרים:",
-       "restrictionsfield-help": "כתובת IP אחת או טווח CIDR אחד בשורה. כדי לאפשר את הכול, ניתן להשתמש ב:<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "כתובת IP אחת או טווח CIDR אחד בשורה. כדי לאפשר את הכול, ניתן להשתמש ב:<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "שגיאה: $1",
+       "edit-error-long": "שגיאות:\n\n$1"
 }
index 3335a30..e50c57e 100644 (file)
        "nosuchusershort": "Ne postoji suradnik s imenom \"$1\". Provjerite Vaš unos.",
        "nouserspecified": "Molimo navedite suradničko ime.",
        "login-userblocked": "Ovaj je suradnik blokiran. Prijava nije dopuštena.",
-       "wrongpassword": "Lozinka koju ste unijeli nije ispravna. Pokušajte ponovno.",
-       "wrongpasswordempty": "Niste unijeli lozinku. Pokušajte ponovno.",
+       "wrongpassword": "Zaporka koju ste unijeli nije ispravna. Pokušajte ponovno.",
+       "wrongpasswordempty": "Niste unijeli zaporku. Pokušajte ponovno.",
        "passwordtooshort": "Zaporka mora sadržavati najmanje {{PLURAL:$1|1 znak|$1 znaka|$1 znakova}}.",
        "password-name-match": "Vaša lozinka mora biti različita od Vašeg suradničkog imena.",
        "password-login-forbidden": "Uporaba ovog suradničkog imena i lozinke nije dozvoljena.",
        "wlshowhideanons": "neprijavljene suradnike",
        "wlshowhidepatr": "ophođena uređivanja",
        "wlshowhidemine": "moje promjene",
+       "wlshowhidecategorization": "kategorizaciju stranica",
        "watchlist-options": "Izbornik popisa praćenja",
        "watching": "Pratim...",
        "unwatching": "Prestajem pratiti...",
index cdd7d39..f509379 100644 (file)
        "editpage-cannot-use-custom-model": "Ennek a lapnak a tartalommodellje nem változtatható.",
        "longpageerror": "'''HIBA: Az általad beküldött szöveg {{PLURAL:$1|egy kilobájt|$1 kilobájt}} hosszú, ami több az engedélyezett {{PLURAL:$2|egy kilobájtnál|$2 kilobájtnál}}.\nA szerkesztést nem lehet elmenteni.'''",
        "readonlywarning": "<strong>FIGYELMEZTETÉS: A wiki adatbázisát karbantartás miatt zárolták, ezért most nem fogod tudni elmenteni a szerkesztéseidet!</strong>\nA lap szövegét másold egy szövegfájlba, amit később felhasználhatsz!\n\nAz adatbázist lezáró rendszeradminisztrátor az alábbi magyarázatot adta: $1",
-       "protectedpagewarning": "'''Figyelem: Ez a lap le van védve, így csak adminisztrátori jogosultságokkal rendelkező szerkesztők módosíthatják.'''\nA legutolsó ide vonatkozó naplóbejegyzés alább látható:",
+       "protectedpagewarning": "<strong>Figyelem: Ez a lap védett, így csak adminisztrátori jogosultságokkal rendelkező szerkesztők módosíthatják.</strong>\nA legutolsó ide vonatkozó naplóbejegyzés alább látható:",
        "semiprotectedpagewarning": "'''Megjegyzés:''' ez a lap védett, így regisztrálatlan vagy újonnan regisztrált szerkesztők nem módosíthatják.",
        "cascadeprotectedwarning": "<strong>Figyelem:</strong> ez a lap le van zárva, csak adminisztrátorok szerkeszthetik, mert a következő kaszkádvédelemmel ellátott {{PLURAL:$1|lapon|lapokon}} be van illesztve:",
        "titleprotectedwarning": "'''Figyelem: Ez a lap le van védve, így csak a [[Special:ListGroupRights|megfelelő jogosultságokkal]] rendelkező szerkesztők hozhatják létre.'''\nA legutolsó ide vonatkozó naplóbejegyzés alább látható:",
        "feedback-external-bug-report-button": "A fájl egy technikai feladat",
        "feedback-dialog-title": "Visszajelzés küldése",
        "feedback-dialog-intro": "A visszajelzésedre az alábbi egyszerű űrlapot használhatod. A hozzászólásod a felhasználó neveddel együtt a „$1” oldalon fog megjelenni.",
-       "feedback-error-title": "Hiba",
        "feedback-error1": "Hiba: az API ismeretlen eredménnyel tért vissza",
        "feedback-error2": "Hiba: a szerkesztés nem sikerült",
        "feedback-error3": "Hiba: nem érkezett válasz az API-tól",
index b009e9c..716b82e 100644 (file)
        "newimages-showbots": "Monstrar files incargate per robots",
        "newimages-hidepatrolled": "Celar le files incargate patruliate",
        "noimages": "Nihil a vider.",
+       "gallery-slideshow-toggle": "Alternar miniaturas",
        "ilsubmit": "Cercar",
        "bydate": "per data",
        "sp-newimages-showfrom": "Monstrar nove files a partir del $1 a $2",
        "feedback-thanks": "Gratias! Tu evalutation ha essite publicate in le pagina \"[$2 $1]\".",
        "feedback-thanks-title": "Gratias!",
        "feedback-useragent": "Agente usator:",
-       "searchsuggest-search": "Cercar",
+       "searchsuggest-search": "Cercar in {{SITENAME}}",
        "searchsuggest-containing": "continente...",
        "api-error-autoblocked": "Tu adresse IP ha essite blocate automaticamente, perque illo ha essite usate per un usator blocate.",
        "api-error-badaccess-groups": "Tu non ha le permission de incargar files in iste wiki.",
index d22d1a7..b8a9b97 100644 (file)
        "movelogpagetext": "Di seguito sono elencate le pagine spostate di recente.",
        "movesubpage": "{{PLURAL:$1|Sottopagina|Sottopagine}}",
        "movesubpagetext": "Questa pagina ha $1 {{PLURAL:$1|sottopagina mostrata|sottopagine mostrate}} di seguito.",
+       "movesubpagetalktext": "La corrispondente pagina di discussione ha $1 {{PLURAL:$1|sottopagina mostrata|sottopagine mostrate}} di seguito.",
        "movenosubpage": "Questa pagina non ha sottopagine.",
        "movereason": "Motivo:",
        "revertmove": "ripristina",
        "newimages-showbots": "Mostra caricamenti di bot",
        "newimages-hidepatrolled": "Nascondi caricamenti verificati",
        "noimages": "Non c'è nulla da vedere.",
+       "gallery-slideshow-toggle": "Alterna miniature",
        "ilsubmit": "Ricerca",
        "bydate": "per data",
        "sp-newimages-showfrom": "Mostra i file più recenti a partire dalle ore $2 del $1",
        "feedback-thanks": "Grazie! Il tuo feedback è stato pubblicato alla pagina \"[$2 $1]\".",
        "feedback-thanks-title": "Grazie!",
        "feedback-useragent": "Agente utente:",
-       "searchsuggest-search": "Ricerca",
+       "searchsuggest-search": "Cerca all'interno di {{SITENAME}}",
        "searchsuggest-containing": "contenente...",
        "api-error-autoblocked": "Il tuo indirizzo IP è stato bloccato automaticamente, perché è stato utilizzato da un utente bloccato.",
        "api-error-badaccess-groups": "Non sei autorizzato a caricare documenti su questa wiki.",
        "usercssispublic": "Ricorda: le sottopagine CSS non devono contenere dati riservati poichè sono visualizzabili da altri utenti.",
        "restrictionsfield-badip": "Indirizzo IP o intervallo non valido: $1",
        "restrictionsfield-label": "Intervalli IP consentiti:",
-       "restrictionsfield-help": "Un indirizzo IP o intervallo CIDR per linea. Per consentire tutto, utilizza<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "Un indirizzo IP o intervallo CIDR per linea. Per consentire tutto, utilizza<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Errore: $1",
+       "edit-error-long": "Errori:\n\n$1"
 }
index a85c60b..38d9bdb 100644 (file)
        "createacct-benefit-heading": "{{SITENAME}} შექმნილია თქვენნაირი ადამიანების მიერ.",
        "createacct-benefit-body1": "{{PLURAL:$1|რედაქტირება|რედაქტირება}}",
        "createacct-benefit-body2": "{{PLURAL:$1|გვერდი|გვერდი}}",
-       "createacct-benefit-body3": "á\83\91á\83\9dá\83\9aá\83\9d {{PLURAL:$1|á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\98\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aი}}",
+       "createacct-benefit-body3": "á\83\91á\83\9dá\83\9aá\83\9d {{PLURAL:$1|á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\9dá\83 á\83\98\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\9dá\83 ი}}",
        "badretype": "თქვენს მიერ შეყვანილი პაროლები ერთმანეთს არ ემთხვევა.",
        "usernameinprogress": "ამ მომხმარებლისათვის ანგარიში იქმნება. გთხოვთ, დაიცადეთ.",
        "userexists": "ეს სახელი უკვე გამოყენებულია.\nგთხოვთ, აირჩიეთ სხვა.",
        "feedback-external-bug-report-button": "ტექნიკური დავალების გაგზავნა",
        "feedback-dialog-title": "გამოხმაურების გაგზავნა",
        "feedback-dialog-intro": "თქვენ შეგიძლიათ ისარგებლოთ ქვემოთ არსებული მარტივი ფორმით, რათა დატოვოთ თქვენი გამოძახილი. კომენტარები თქვენ მომხმარებლის სახელთან ერთად დამატებული იქნება \"$1\" გვერდზე",
-       "feedback-error-title": "შეცდომა",
        "feedback-error1": "შეცდომა. API-ს მოულოდნელი რეზულტატი.",
        "feedback-error2": "შეცდომა: რედაქტირება ვერ განხორციელდა",
        "feedback-error3": "შეცდომა. არ არის API-ს პასუხი .",
index f09c38b..c3926de 100644 (file)
@@ -65,6 +65,7 @@
        "tog-watchlisthidebots": "ವೀಕ್ಷಣಾಪಟ್ಟಿಯಲ್ಲಿ ಬಾಟ್ ಸಂಪಾದನೆಗಳನ್ನು ಅಡಗಿಸು",
        "tog-watchlisthideminor": "ಚಿಕ್ಕ ಬದಲಾವಣೆಗಳನ್ನು ವೀಕ್ಷಣಾ ಪಟ್ಟಿಯಿಂದ ಅಡಗಿಸು",
        "tog-watchlisthideliu": "ಲಾಗ್ ಇನ್ ಆಗಿರುವ ಸದಸ್ಯರ ಸಂಪಾದನೆಗಳನ್ನು ವೀಕ್ಷಣಾಪಟ್ಟಿಯಲ್ಲಿ ಅಡಗಿಸು",
+       "tog-watchlistreloadautomatically": "ಯಾವುದೇ ಫಿಲ್ಟರು ಬದಲಾದಾಗ ವೀಕ್ಷಣಾಪಟ್ಟಿ ಮತ್ತೆ ಲೋಡ್ ಆಗಲಿ (ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಇರಬೇಕು)",
        "tog-watchlisthideanons": "ಅನಾಮಧೇಯ ಬಳಕೆದಾರರ ಸಂಪಾದನೆಗಳನ್ನು ವೀಕ್ಷಣಾಪಟ್ಟಿಯಲ್ಲಿ ಅಡಗಿಸು",
        "tog-watchlisthidepatrolled": "ವೀಕ್ಷಣಾ ಪತ್ತಿಯಲ್ಲಿ ಹಸ್ತುಕದರ್ ಬದಲಾವಣೆಗಳನ್ನು ಅದಗಿಸು",
        "tog-watchlisthidecategorization": "ಪುಟಗಳ ವರ್ಗೀಕರಣವನ್ನು ಅಡಗಿಸು",
        "actionthrottled": "ಕ್ರಿಯೆಯನ್ನು ನಿಯಂತ್ರಿಸಲಾಗಿದೆ",
        "actionthrottledtext": "ಸ್ಪ್ಯಾಮ್ ವಿರೋಧಿ ವಿಧಾನದ ಪ್ರಕಾರ, ನಿಮ್ಮನ್ನು ಸ್ವಲ್ಪ ಸಮಯದಲ್ಲಿ ಬಹಳ ಸಲ ಈ ಕ್ರಿಯೆಯನ್ನು ಮಾಡುವುದರಿಂದ ನಿಯಂತ್ರಿಸಲಾಗಿದೆ ಮತ್ತು ನೀವು ಸೀಮೆಯನ್ನು ಮಿರಿದ್ದಿರಿ. ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.",
        "protectedpagetext": "ಈ ಪುಟವನ್ನು ಸಂಪಾದನೆ ಮಾಡಲಾಗದಂತೆ ಸಂರಕ್ಷಿಸಲಾಗಿದೆ.",
-       "viewsourcetext": "ಈ ಪುಟದ ಮೂಲವನ್ನು ನೀವು ವೀಕ್ಷಿಸಬಹುದು ಮತ್ತು ನಕಲು ಮಾಡಬಹುದು:",
-       "viewyourtext": "ನೀವು \"ನಿಮ್ಮ ಸಂಪಾದನೆಗಳ\"ನ್ನು ವಿಕ್ಷಿಸಿ ಮತ್ತು ಅದರ ಮೂಲವನ್ನು ಈ ಹಾಳೆಗೆ ನಕಲಿಸಬಹುದು:",
+       "viewsourcetext": "ಈ ಪುಟದ ಮೂಲವನ್ನು ನೀವು ವೀಕ್ಷಿಸಬಹುದು ಮತ್ತು ನಕಲು ಮಾಡಬಹುದು.",
+       "viewyourtext": "ನೀವು <strong>ನಿಮ್ಮ ಸಂಪಾದನೆಗಳನ್ನು</strong> ವೀಕ್ಷಿಸಿ ಮತ್ತು ಅದರ ಮೂಲವನ್ನು ಈ ಹಾಳೆಗೆ ನಕಲಿಸಬಹುದು.",
        "protectedinterface": "ಈ ಪುಟವು ತಾಂತ್ರಿಕತೆಗೆ ಸಂಪರ್ಕ ಪಠ್ಯವನ್ನು ವಿಕಿಯಲ್ಲಿ ಒದಗಿಸುತ್ತದೆ, ಹಾಗು ದುರುಪಯೋಗ ಆಗದಿರಲೆಂದು ಇದನ್ನು ಸಂರಕ್ಷಿಸಲಾಗಿದೆ. ಎಲ್ಲ ವಿಕಿಗಳಿಗೆ ಭಾಷಾಂತರವನ್ನು ಕೂಡಿಸಲು ಹಾಗು ಬದಲಿಸಲು, [https://translatewiki.net/ translatewiki.net], the MediaWiki localisation ಯೋಜನೆಯನ್ನು ಉಪಯೊಗಿಸಿ",
        "editinginterface": "'''ಎಚ್ಚರಿಕೆ:''' ನೀವು ತಂತ್ರಾಂಶವು ತಾಣವನ್ನು ಪ್ರದರ್ಶಿಸಲು ಉಪಯೋಗಿಸುವ ಪಠ್ಯವನ್ನು ಹೊಂದಿರುವ ಪುಟವೊಂದನ್ನು ಸಂಪಾದಿಸುತ್ತಿರುವಿರಿ.\nಈ ಪುಟದಲ್ಲಾಗುವ ಬದಲಾವಣೆಗಳು ಇತರ ಬಳಕೆದಾರರಿಗೆ ತಾಣವು ಕಾಣುವ ರೀತಿಯನ್ನು ಬದಲಾಯಿಸುತ್ತದೆ.\nಅನುವಾದಗಳನ್ನು ಮಾಡುತ್ತಿದ್ದರೆ, ದಯವಿಟ್ಟು ಮೀಡಿಯವಿಕಿಯ ಪ್ರಾಂತೀಯತೆ ಯೋಜನೆ [https://translatewiki.net/ translatewiki.net], the MediaWiki localisation project ಯೋಜನೆಯನ್ನು ಉಪಯೊಗಿಸಿ",
        "cascadeprotected": "ಈ ಪುಟವು ಸಂಪಾದನೆ ಮಾಡಲಾಗದಂತೆ ಸಂರಕ್ಷಿಸಲಾಗಿದೆ. ಇದಕ್ಕೆ ಕಾರಣ ಈ ಪುಟವನ್ನು ಈ ಕೆಳಗಿನ ತಡಸಲು-ಸಂರಕ್ಷಣೆ ಅಳವಡಿಸಲಾದ {{PLURAL:$1|ಪುಟದಲ್ಲಿ|ಪುಟಗಳಲ್ಲಿ}} ಉಪಯೋಗಿಸಲಾಗಿದೆ:\n$2",
        "mypreferencesprotected": "ನಿಮ್ಮ ಆಯ್ಕೆಗಳನ್ನು  ಸಂಪಾದಿಸಲು ನಿಮಗೆ ಅನುಮತಿ ಇಲ್ಲ",
        "ns-specialprotected": "ವಿಶೇಷ ಪುಟಗಳನ್ನು ಸಂಪಾದಿಸಲು ಆಗುವುದಿಲ್ಲ.",
        "titleprotected": "ಈ ಹೆಸರಿನ ಪುಟವನ್ನು ಸೃಷ್ಟಿಸಲಾಗದಂತೆ [[User:$1|$1]] ಅವರು ಸಂರಕ್ಷಿಸಿದ್ದಾರೆ.\nಸಂರಕ್ಷಣೆಗೆ ನೀಡಿರುವ ಕಾರಣ: <em>$2</em>.",
-       "filereadonlyerror": "\"$1\" ಕಡತವು ಓದಲು ಮಾತ್ರ ಸಾದ್ಯವಿರುವ ರೀತಿಯಲ್ಲಿರುವ\"$2\" ಸಂಪುಟದಲ್ಲಿರುವುದರಿಂದ ಇದನ್ನು  ಮಾರ್ಪಡಿಸಲು ಸಾದ್ಯವಾಗುತ್ತಿಲ್ಲ.\nಇದನ್ನು ಬದ್ದಗೊಳಿಸಿರುವ ನಿರ್ವಾಹಕರು \"$3\" ಈ ವಿವರಣೆಯನ್ನು ನೀಡುತ್ತಿದ್ದಾರೆ.",
+       "filereadonlyerror": "\"$1\" ಕಡತವು ಓದಲು ಮಾತ್ರ ಸಾದ್ಯವಿರುವ ರೀತಿಯಲ್ಲಿರುವ \"$2\" ಸಂಪುಟದಲ್ಲಿ ಇರುವುದರಿಂದ ಇದನ್ನು  ಮಾರ್ಪಡಿಸಲು ಸಾದ್ಯವಾಗುತ್ತಿಲ್ಲ.\nಇದನ್ನು ಬದ್ದಗೊಳಿಸಿರುವ ನಿರ್ವಾಹಕರು ಈ ವಿವರಣೆಯನ್ನು ನೀಡುತ್ತಿದ್ದಾರೆ: \"$3\"",
        "invalidtitle-knownnamespace": "\"$2\"ನೇಮ್ ಸ್ಪೇಸ್ ಮತ್ತು \"$3\"ಪಠ್ಯದೊಂದಿಗೆ ಅಸಮಂಜಸ ತಲೆಬರಹ",
        "invalidtitle-unknownnamespace": "$1ನೇಮ್ ಸ್ಪೇಸ್ ಮತ್ತು \"$2\"ಪಠ್ಯದೊಂದಿಗೆ ಅಸಮಂಜಸ ತಲೆಬರಹ",
        "exception-nologin": "ಲಾಗಿನ್ ಆಗಿಲ್ಲ",
-       "exception-nologin-text": "ಈ ಪುಟ ಅಥವಾ ಚಟುವಟಿಕೆಗೆ ನೀವು ಈ ವಿಕಿಗೆ [[Special:Userlogin|ಲಾಗಿನ್]] ಆಗಿರಬೇಕಾಗಿರುತ್ತದೆ.",
+       "exception-nologin-text": "ಈ ಪುಟವನ್ನು ವೀಕ್ಷಿಸಲು ಅಥವ ಚಟುವಟಿಕೆಯನ್ನು ಮಾಡಲು ಲಾಗಿನ್ ಆಗಬೇಕು.",
        "exception-nologin-text-manual": "ಈ ಪುಟ ಅಥವಾ ಚಟುವಟಿಕೆಗೆ $1 ಮಾಡಿ",
        "virus-badscanner": "ಅಸಮಂಜಸ ವಿನ್ಯಾಸ:ಅಪರಿಚಿತ ವೈರಸ್ ಸ್ಕಾನರ್:''$1''",
        "virus-scanfailed": "ಸ್ಕಾನ್ ವಿಫಲ (code $1)",
        "virus-unknownscanner": "ಅಪರಿಚಿತ ವೈರಾಣುನಾಶಕ:",
        "logouttext": "'''ನೀವು ಈಗ ಲಾಗ್ ಔಟ್ ಆಗಿರುವಿರಿ.'''\n \nಗಮನಿಸಿ: ನಿಮ್ಮ ಬ್ರೌಸರ್‍ನ cache ಅನ್ನು ಅಳಿಸುವವರೆಗೂ ಕೆಲವು ಪುಟಗಳು ನೀವಿನ್ನೂ ಲಾಗ್ ಇನ್ ಆಗಿರುವಂತೆ ಪ್ರದರ್ಶಿತವಾಗಬಹುದು.",
+       "cannotlogoutnow-title": "ಈಗ ಲಾಗ್ ಔಟ್ ಮಾಡಲಾಗುತ್ತಿಲ್ಲ",
+       "cannotlogoutnow-text": "$1 ಬಳಸುವಾಗ ಲಾಗ್ ಔಟ್ ಆಗಲು ಸಾಧ್ಯವಿಲ್ಲ.",
        "welcomeuser": "ಸುಸ್ವಾಗತ,$1!",
        "welcomecreation-msg": "ನಿಮ್ಮ ಖಾತೆ ತೆರೆಯಲಾಗಿದೆ.ನಿಮ್ಮ [[Special:Preferences|{{SITENAME}} preferences]]ಬದಲಾಯಿಸಲು ಮರೆಯಬೇಡಿ.",
        "yourname": "ನಿಮ್ಮ ಬಳಕೆಯ ಹೆಸರು",
        "createacct-yourpasswordagain-ph": "ಪ್ರವೇಶಪದವನ್ನು ಮತ್ತೊಮ್ಮೆ ನಮೂದಿಸಿ",
        "userlogin-remembermypassword": "ನನ್ನನ್ನು ಲಾಗಿನ್ ಆಗಿಯೇ ಇಡಿ",
        "userlogin-signwithsecure": "ಸುರಕ್ಷಿತವಾದ ಕನೆಕ್ಷನ್ ಉಪಯೋಗಿಸಿ.",
+       "cannotlogin-title": "ಲಾಗ್ ಇನ್ ಮಾಡಲಾಗುತ್ತಿಲ್ಲ",
+       "cannotlogin-text": "ಲಾಗ್ ಇನ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ.",
+       "cannotloginnow-title": "ಈಗ ಲಾಗ್ ಇನ್ ಮಾಡಲು ಆಗುತ್ತಿಲ್ಲ",
+       "cannotloginnow-text": "$1 ಬಳಸುವಾಗ ಲಾಗ್ ಇನ್ ಆಗಲು ಸಾಧ್ಯವಿಲ್ಲ.",
+       "cannotcreateaccount-title": "ಖಾತೆಗಳನ್ನು ಸೃಷ್ಟಿಸಲಾಗುತ್ತಿಲ್ಲ",
        "yourdomainname": "ನಿಮ್ಮ ಕ್ಷೇತ್ರ:",
        "password-change-forbidden": "ನೀವು ಈ ವಿಕಿಯಲ್ಲಿ ಪ್ರವೇಶಪದವನ್ನು ಬದಲಾಯಿಸಲು ಸಾದ್ಯವಿಲ್ಲ.",
        "login": "ಲಾಗ್ ಇನ್",
        "userlogin-resetlink": "ನಿಮ್ಮ ಲಾಗಿನ್ ವಿವರಗಳನ್ನು ಮರೆತಿದ್ದೀರಾ?",
        "userlogin-resetpassword-link": "ನಿಮ್ಮ ಪ್ರವೇಶಪದ ಮರೆತಿರೇ?",
        "userlogin-helplink2": "ಲಾಗಿನ್ ಆಗಲು ಸಹಾಯ",
+       "userlogin-reauth": "ನೀವು {{GENDER:$1|$1}} ಎಂದು ಖಾತ್ರಿ ಮಾಡಲು ಮತ್ತೆ ಲಾಗ್ ಇನ್ ಆಗಬೇಕು.",
        "userlogin-createanother": "ಇನ್ನೊಂದು ಖಾತೆಯನ್ನು ಸೃಷ್ಟಿಸಿ",
        "createacct-emailrequired": "ಇ-ಮೇಲ್ ವಿಳಾಸ:",
        "createacct-emailoptional": "ಮಿಂಚಂಚೆ ವಿಳಾಸ (ಐಚ್ಛಿಕ)",
        "createacct-reason": "ಕಾರಣ",
        "createacct-reason-ph": "ನೀವು ಯಾಕೆ ಇನ್ನೊಂದು ಖಾತೆ ತೆರೆಯುತ್ತಿದ್ದೀರಿ",
        "createacct-submit": "ಖಾತೆಯನ್ನು ಸೃಷ್ಟಿಸಿ",
-       "createacct-another-submit": "ಇನ್ನು ಒಂದು ಖಾತ ಮಾಡಿ",
+       "createacct-another-submit": "ಖಾತೆಯನ್ನು ಸೃಷ್ಟಿಸಿ",
+       "createacct-continue-submit": "ಖಾತೆಯ ಸೃಷ್ಟಿಯನ್ನು ಮುಂದುವರೆಸಿ",
+       "createacct-another-continue-submit": "ಖಾತೆಯ ಸೃಷ್ಟಿಯನ್ನು ಮುಂದುವರೆಸಿ",
        "createacct-benefit-heading": "{{SITENAME}} ನಿಮ್ಮಂತಹ ಜನರಿಂದಲೇ ಮಾಡಿದ್ದು.",
        "createacct-benefit-body1": "{{PLURAL:$1|ಸಂಪಾದನೆ|ಸಂಪಾದನೆಗಳು}}",
        "createacct-benefit-body2": "{{PLURAL:$1|ಪುಟ|ಪುಟಗಳು}}",
        "pt-createaccount": "ಹೊಸ ಖಾತೆ ತೆರೆಯಿರಿ",
        "pt-userlogout": "ಲಾಗ್ ಔಟ್",
        "changepassword": "ಪ್ರವೇಶ ಪದ ಬದಲಾಯಿಸಿ",
-       "resetpass_announce": "ನà³\80ವà³\81 à²¤à²¾à²¤à³\8dà²\95ಾಲಿà²\95 à²\87-à²\85à²\82à²\9aà³\86 à²\95à³\8bಡà³\8d à²\85ನà³\8dನà³\81 à²\89ಪಯà³\8bà²\97ಿಸಿ à²²à²¾à²\97à³\8d à²\87ನà³\8d à²\86à²\97ಿರà³\81ವಿರಿ.\nಲಾà²\97à³\8d à²\87ನà³\8d à²ªà³\82ರà³\8dಣà²\97à³\8aಳಿಸಲà³\81 à²¨à³\80ವಿಲà³\8dಲ à²¹à³\8aಸ à²ªà³\8dರವà³\87ಶಪದ à²¨à³\80ಡಬà³\87à²\95à³\81:",
+       "resetpass_announce": "ಲಾà²\97à³\8d à²\87ನà³\8d à²ªà³\82ರà³\8dಣà²\97à³\8aಳಿಸಲà³\81 à²¨à³\80ವà³\81 à²¹à³\8aಸ à²ªà³\8dರವà³\87ಶಪದವನà³\8dನà³\81 à²¨à²®à³\82ದಿಸಬà³\87à²\95à³\81.",
        "resetpass_header": "ಖಾತೆಯ ಪ್ರವೇಶಪದ ಬದಲಾಯಿಸಿ",
        "oldpassword": "ಹಳೆಯ ಪ್ರವೇಶ ಪದ",
        "newpassword": "ಹೊಸ ಪ್ರವೇಶ ಪದ",
        "retypenew": "ಹೊಸ ಪ್ರವೇಶಪದವನ್ನು ಮತ್ತೆ ಟೈಪಿಸು:",
        "resetpass_submit": "ಪ್ರವೇಶ ಪದವನ್ನು ನಿಶ್ಚಯಿಸಿ ಲಾಗ್ ಇನ್ ಆಗಿ",
-       "changepassword-success": "ನಿಮ್ಮ ಪ್ರವೇಶ ಪದವನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಬದಲಾಯಿಸಲಾಗಿದೆ. ಈಗ ನಿಮ್ಮನ್ನು ಲಾಗ್ ಇನ್ ಮಾಡಲಾಗುತ್ತಿದೆ...",
+       "changepassword-success": "ನಿಮ್ಮ ಪ್ರವೇಶಪದವನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ!",
+       "changepassword-throttled": "ನೀವು ಬಹಳ ಸಾರಿ ಲಾಗ್ ಇನ್ ಆಗಲು ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. \nಮತ್ತೆ ಪ್ರಯತ್ನಿಸಲು $1 ಕಾಯಬೇಕು.",
+       "botpasswords": "ಬಾಟ್ ಪ್ರವೇಶ ಪದಗಳು",
        "resetpass_forbidden": "ಪ್ರವೇಶಪದಗಳನ್ನು ಬದಲಾಯಿಸುವಂತಿಲ್ಲ.",
        "resetpass-no-info": "ನೀವು ಈ ಪುಟವನ್ನು ನೇರತಲುಪಲು ಲಾಗಿನ್ ಆಗಿರುವುದು ಆವಶ್ಯಕ.",
        "resetpass-submit-loggedin": "ಪ್ರವೇಶಪದ ಬದಲಾಯಿಸು",
        "sig_tip": "ಸಮಯಮುದ್ರೆಯೊಂದಿಗೆ ನಿಮ್ಮ ಸಹಿ",
        "hr_tip": "ಅಡ್ಡ ಗೆರೆ (ಆದಷ್ಟು ಕಡಿಮೆ ಉಪಯೋಗಿಸಿ)",
        "summary": "ಸಾರಾಂಶ:",
-       "subject": "ವಿಷಯ/ತಲೆಬರಹ:",
+       "subject": "ವಿಷಯ:",
        "minoredit": "ಇದು ಚುಟುಕಾದ ಬದಲಾವಣೆ",
        "watchthis": "ಈ ಪುಟವನ್ನು ವೀಕ್ಷಿಸಿ",
        "savearticle": "ಪುಟವನ್ನು ಉಳಿಸಿ",
+       "savechanges": "ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಿ",
        "publishpage": "ಪುಟವನ್ನು ಪ್ರಕಟಿಸು",
        "publishchanges": "ಬದಲಾವಣೆಗಳನ್ನು ಪ್ರಕಟಿಸು",
        "preview": "ಮುನ್ನೋಟ",
        "showpreview": "ಮುನ್ನೋಟ ತೋರಿಸು",
        "showdiff": "ಬದಲಾವಣೆಗಳನ್ನು ತೋರಿಸು",
-       "anoneditwarning": "'''ಎಚ್ಚರ:''' ನೀವು ಲಾಗ್ ಇನ್ ಆಗಿಲ್ಲ. ನಿಮ್ಮ ಐಪಿ ವಿಳಾಸವು ಪುಟದ ಸಂಪಾದನೆಗಳ ಇತಿಹಾಸದಲ್ಲಿ ದಾಖಲಾಗುತ್ತದೆ.",
+       "blankarticle": "<strong>ಎಚ್ಚರಿಕೆ:</strong> ನೀವು ಸೃಷ್ಟಿಸುತ್ತಿರುವ ಪುಟ ಖಾಲಿ ಇದೆ.\n\"{{int:savearticle}}\" ಅನ್ನು ಮತ್ತೆ ಕ್ಲಿಕ್ಕಿಸಿದರೆ, ಏನೂ ಇರದಂತೆಯೆ ಈ ಪುಟವು ಸೃಷ್ಟಿಯಾಗುತ್ತದೆ.",
+       "anoneditwarning": "<strong>ಎಚ್ಚರ:</strong> ನೀವು ಲಾಗ್ ಇನ್ ಆಗಿಲ್ಲ. ನೀವು ಸಂಪಾದನೆ ಮಾಡಿದಲ್ಲಿ ನಿಮ್ಮ ಐಪಿ ವಿಳಾಸವು ಎಲ್ಲರಿಗೂ ಕಾಣಲು ಸಿಗುತ್ತದೆ. ನೀವು <strong>[$1 ಲಾಗ್ ಇನ್ ಆದರೆ]</strong> ಅಥವ <strong>[$2 ಹೊಸ ಖಾತೆಯನ್ನು ಸೃಷ್ಟಿಸಿದರೆ]</strong>, ನಿಮ್ಮ ಸಂಪಾದನೆಗಳನ್ನು ನೀವು ನಿಮ್ಮ ಬಳಕೆದಾರ ಹೆಸರಿನ ಅಡಿಯಲ್ಲಿ ಪ್ರದರ್ಶಿಸಬಹುದು.",
        "anonpreviewwarning": "''ನೀವು ಲಾಗಿನ್ ಆಗಿಲ್ಲ . ಉಳಿಸಲು ಪ್ರಯತ್ನಿಸಿದಾಗ ನಿಮ್ಮ IP ವಿಳಾಸವನ್ನು ಈ ಪುಟದ ಸಂಪಾದನೆ ಇತಿಹಾಸದಲ್ಲಿ ನಮೂದಿಸಲಗುವುದು.''",
        "missingsummary": "'''ಗಮನಿಸಿ:''' ನಿಮ್ಮ ಸಂಪಾದನೆಯ ಸಾರಾಂಶವನ್ನು ನೀವು ನೀಡಿಲ್ಲ. ಮತ್ತೊಮ್ಮೆ \"ಉಳಿಸು\" ಗುಂಡಿಯನ್ನು ಒತ್ತಿದರೆ, ಸಾರಾಂಶವಿಲ್ಲದೆಯೇ ನಿಮ್ಮ ಸಂಪಾದನೆಯನ್ನು ಉಳಿಸಲಾಗುವುದು.",
        "missingcommenttext": "ಕೆಳಗೆ ಒಂದು ಟಿಪ್ಪಣಿ ನಮೂದಿಸಿ",
-       "missingcommentheader": "'''ಗಮನಿಸಿ:''' ಈ ವ್ಯಾಖ್ಯಾನಕ್ಕೆ ವಿಷಯ ಅಥವ ತಲೆಬರಹ ನೀವು ಸೂಚಿಸಿಲ್ಲ. ನೀವು \"{{int:savearticle}}\"\nಮತ್ತೊಮೆ ಒತ್ತಿದರೆ ನಿಮ್ಮ ಸಂಪಾದನೆಯನ್ನು ಹಾಗೆಯೇ ಉಳಿಸಲಾಗುವುದು.",
+       "missingcommentheader": "<strong>ಗಮನಿಸಿ:</strong> ನಿಮ್ಮ ಸಂಪಾದನೆಯ ಸಾರಾಂಶವನ್ನು ನೀವು ನೀಡಿಲ್ಲ. ಮತ್ತೊಮ್ಮೆ \"{{int:savearticle}}\" ಅನ್ನು ಒತ್ತಿದರೆ, ಸಾರಾಂಶವಿಲ್ಲದೆಯೇ ನಿಮ್ಮ ಸಂಪಾದನೆಯನ್ನು ಉಳಿಸಲಾಗುವುದು.",
        "summary-preview": "ತಾತ್ಪರ್ಯ ಮುನ್ನೋಟ:",
        "subject-preview": "ವಿಷಯದ ಮುನ್ನೋಟ:",
        "blockedtitle": "ಈ ಸದಸ್ಯರನ್ನು ತಡೆ ಹಿಡಿಯಲಾಗಿದೆ.",
        "whitelistedittext": "ಪುಟಗಳನ್ನು ಸಂಪಾದಿಸಲು ನೀವು $1 ಆಗಬೇಕು.",
        "confirmedittext": "ಪುಟಗಳನ್ನು ಸಂಪಾದಿಸುವ ಮುನ್ನ ನೀವು ನಿಮ್ಮ ಇ-ಅಂಚೆ ವಿಳಾಸವನ್ನು ಧೃಡೀಕರಿಸಬೇಕು.\nದಯವಿಟ್ಟು [[Special:Preferences|ಬಳಕೆದಾರ ಆಯ್ಕೆಗಳು]] ಪುಟದಲ್ಲಿ ತಮ್ಮ ಇ-ಅಂಚೆ ವಿಳಾಸವನ್ನು ನಮೂದಿಸಿ ಮತ್ತು ಧೃಡೀಕರಿಸಿ.",
        "nosuchsectiontitle": "ಆ ಹೆಸರಿನ ವಿಭಾಗ ಯಾವುದೂ ಇಲ್ಲ",
-       "nosuchsectiontext": "ನೀವು ಅಸ್ಥಿತ್ವದಲ್ಲಿ ಇರದ ಒಂದು ವಿಭಾಗವನ್ನು ಸಂಪಾದಿಸಲು ಪ್ರಯತ್ನಿಸಿದಿರಿ.",
+       "nosuchsectiontext": "ನೀವು ಅಸ್ಥಿತ್ವದಲ್ಲಿ ಇರದ ಒಂದು ವಿಭಾಗವನ್ನು ಸಂಪಾದಿಸಲು ಪ್ರಯತ್ನಿಸಿದಿರಿ.\nನೀವು ಪುಟವನ್ನು ವೀಕ್ಷಿಸುವಾಗ ಆ ವಿಭಾಗವು ಸ್ಥಳಾಂತರಗೊಂಡಿರಬಹುದು ಅಥವ ಅಳಿಸಲ್ಪಟ್ಟಿರಬಹುದು.",
        "loginreqtitle": "ಲಾಗಿನ್ ಆಗಬೇಕು",
        "loginreqlink": "ಲಾಗ್ ಇನ್",
        "loginreqpagetext": "ಇತರ ಪುಟಗಳನ್ನು ನೋಡಲು ನೀವು $1 ಆಗಬೇಕು.",
        "newarticle": "(ಹೊಸತು)",
        "newarticletext": "ಇನ್ನೂ ಅಸ್ಥಿತ್ವದಲ್ಲಿ ಇರದ ಪುಟದ ಲಿಂಕ್ ಅನ್ನು ನೀವು ಒತ್ತಿರುವಿರಿ.\nಈ ಪುಟವನ್ನು ಸೃಷ್ಟಿಸಲು ಕೆಳಗಿನ ಚೌಕದಲ್ಲಿ ಬರೆಯಲು ಆರಂಭಿಸಿರಿ.\n(ಹೆಚ್ಚು ಮಾಹಿತಿಗೆ [$1 ಸಹಾಯ ಪುಟ] ನೋಡಿ).\nಈ ಪುಟಕ್ಕೆ ನೀವು ತಪ್ಪಾಗಿ ಬಂದಿದ್ದಲ್ಲಿ ನಿಮ್ಮ ಬ್ರೌಸರ್‍ನ '''back''' ಬಟನ್ ಅನ್ನು ಒತ್ತಿ.",
        "anontalkpagetext": "----''ಇದು ಖಾತೆಯೊಂದನ್ನು ಹೊಂದಿರದ ಅನಾಮಧೇಯ ಬಳಕೆದಾರರೊಬ್ಬರ ಚರ್ಚೆ ಪುಟ.\nಖಾತೆಯಿಲ್ಲದಿರುವುದರಿಂದ ಅವರನ್ನು ಗುರುತಿಸಲು ಅವರ IP ವಿಳಾಸವನ್ನು ಉಪಯೋಗಿಸುತ್ತಿದ್ದೇವೆ.\nಈ ರೀತಿಯ IP ವಿಳಾಸವು ಅನೇಕ ಬಳಕೆದಾರರಿಂದ ಉಪಯೋಗದಲ್ಲಿರಬಹುದು.\nನೀವು ಅನಾಮಧೇಯ ಬಳಕೆದಾರರಾಗಿದ್ದಲ್ಲಿ, ಹಾಗು ನಿಮಗೆ ಸಂಬಂಧವಿಲ್ಲದಂತ ಸಂದೇಶಗಳು ಬರುತ್ತಿವೆ ಎಂದು ಅನಿಸಿದರೆ, ಮುಂದೆ ಬೇರೆ ಅನಾಮಧೇಯ ಬಳಕೆದಾರರೊಂದಿಗೆ ತಪ್ಪಾಗಿ ಗುರುತಿಸಬಾರದೆಂದಿದ್ದರೆ ದಯವಿಟ್ಟು [[Special:CreateAccount|ಸದಸ್ಯರಾಗಿ]] ಅಥವ [[Special:UserLogin|ಲಾಗ್ ಇನ್ ಆಗಿ]].''",
-       "noarticletext": "à²\88 à²ªà³\81à²\9fದಲà³\8dಲಿ à²¸à²¦à³\8dಯà²\95à³\8dà²\95à³\86 à²\8fನà³\82 à²\87ಲà³\8dಲ.\nನà³\80ವà³\81 à²\87ತರ à²ªà³\81à²\9fà²\97ಳಲà³\8dಲಿ [[Special:Search/{{PAGENAME}}|à²\88 à²¹à³\86ಸರನà³\8dನà³\81 à²¹à³\81ಡà³\81à²\95ಬಹà³\81ದà³\81]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} à²¸à²\82ಬà²\82ಧಿತ à²¦à²¾à²\96ಲà³\86à²\97ಳನà³\8dನà³\81 à²¹à³\81ಡà³\81à²\95ಬಹà³\81ದà³\81],\nà²\85ಥವ [{{fullurl:{{FULLPAGENAME}}|action=edit}} à²\88 à²ªà³\81à²\9fವನà³\8dನà³\81 à²¸à²\82ಪಾದಿಸಬಹುದು]</span>.",
-       "noarticletext-nopermission": "ಈ ಪುಟದಲ್ಲಿ ಸದ್ಯಕ್ಕೆ ಯಾವ ಪಠ್ಯವೂ ಇಲ್ಲ.\nನೀವು ಇತರ ಪುಟಗಳಲ್ಲಿ [[ವಿಶೇಷ:Search/{{PAGENAME}}|ಈ ಶೀರ್ಷಿಕೆಗಾಗಿ ಹುಡುಕಬಹುದು]],\nಅಥವಾ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ಸಂಬಂಧಿಸಿದ ದಾಖಲಾತಿ ಹುಡುಕಬಹುದು]</span>, ಆದರೆ ನಿಮಗೆ ಈ ಪುಟವನ್ನು ಸಂಪಾದಿಸಲು ಅನುಮತಿಯಿಲ್ಲ.",
+       "noarticletext": "à²\88 à²ªà³\81à²\9fದಲà³\8dಲಿ à²¸à²¦à³\8dಯà²\95à³\8dà²\95à³\86 à²\8fನà³\82 à²\87ಲà³\8dಲ.\nನà³\80ವà³\81 à²\87ತರ à²ªà³\81à²\9fà²\97ಳಲà³\8dಲಿ [[Special:Search/{{PAGENAME}}|à²\88 à²¹à³\86ಸರನà³\8dನà³\81 à²¹à³\81ಡà³\81à²\95ಬಹà³\81ದà³\81]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} à²¸à²\82ಬà²\82ಧಿತ à²¦à²¾à²\96ಲà³\86à²\97ಳನà³\8dನà³\81 à²¹à³\81ಡà³\81à²\95ಬಹà³\81ದà³\81],\nà²\85ಥವ [{{fullurl:{{FULLPAGENAME}}|action=edit}} à²\88 à²ªà³\81à²\9fವನà³\8dನà³\81 à²¸à³\83ಷà³\8dà²\9fಿಸಬಹುದು]</span>.",
+       "noarticletext-nopermission": "ಈ ಪುಟದಲ್ಲಿ ಸದ್ಯಕ್ಕೆ ಯಾವ ಪಠ್ಯವೂ ಇಲ್ಲ.\nನೀವು ಇತರ ಪುಟಗಳಲ್ಲಿ [[Special:Search/{{PAGENAME}}|ಈ ಶೀರ್ಷಿಕೆಗಾಗಿ ಹುಡುಕಬಹುದು]], ಅಥವಾ <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ಸಂಬಂಧಿಸಿದ ದಾಖಲೆಗಳನ್ನು ಹುಡುಕಬಹುದು]</span>, ಆದರೆ ನಿಮಗೆ ಈ ಪುಟವನ್ನು ಸೃಷ್ಟಿಸಲು ಅನುಮತಿಯಿಲ್ಲ.",
        "userpage-userdoesnotexist": "ಬಳಕೆದಾರ ಖಾತೆ \"<nowiki>$1</nowiki>\" ದಾಖಲಾಗಿಲ್ಲ. ನೀವು ಇದೇ ಪುಟವನ್ನು ಸೃಷ್ಟಿ/ಸಂಪಾದನೆ ಮಾಡಬೇಕೆಂದಿರುವಿರಿ ಎಂದು ಖಾತ್ರಿ ಮಾಡಿಕೊಳ್ಳಿ.",
        "blocked-notice-logextract": "ಈ ಬಳಕೆದಾರರನ್ನು  ಪ್ರಸ್ತುತವಾಗಿ  ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ. \nಇತ್ತೀಚಿನ  ನಿರ್ಬಂಧನೆಯ ದಾಖಲೆಯನ್ನು ಉಲ್ಲೇಖಕ್ಕಾಗಿ ಕೆಳಗೆ ಕೊಟ್ಟಿದೆ:",
        "usercssyoucanpreview": "'''ಗಮನಿಸಿ:''' ಉಳಿಸುವ ಮುನ್ನ 'ಮುನ್ನೋಟ' ಗುಂಡಿಯನ್ನು ಉಪಯೋಗಿಸಿ ನಿಮ್ಮ ಹೊಸ CSS ಅನ್ನು ಪ್ರಯೋಗ ಮಾಡಿ.",
        "revertmerge": "ಸೇರ್ಪಡೆಯನ್ನು ತೊಡೆದುಹಾಕು",
        "mergelogpagetext": "ಒಂದು ಪುಟದ ಇತಿಹಾಸವನ್ನು ಇನ್ನೊಂದರೊಳಗೆ ಇತ್ತೀಚೆಗೆ ಸೇರ್ಪಡೆ ಮಾಡಲಾಗಿರುವ ಪಟ್ಟಿ ಕೆಳಗಿದೆ.",
        "history-title": "\"$1\" ಪುಟದ ಬದಲಾವಣೆಗಳ ಇತಿಹಾಸ",
+       "difference-title": "\"$1\" ಆವೃತ್ತಿಗಳ ಮಧ್ಯದ ಬದಲಾವಣೆಗಳು",
        "lineno": "$1 ನೇ ಸಾಲು:",
        "compareselectedversions": "ಆಯ್ಕೆ ಮಾಡಿದ ಆವೃತ್ತಿಗಳನ್ನು ಹೊಂದಾಣಿಕೆ ಮಾಡಿ ನೋಡಿ",
        "showhideselectedversions": "ಆಯ್ದ ಆವೃತ್ತಿಗಳನ್ನು ತೋರಿಸು/ಅಡಗಿಸು",
        "editundo": "ಹಿಂದಿನಂತೆ",
        "diff-empty": "( ಯಾವುದೇ ವ್ಯತ್ಯಾಸವಿಲ್ಲ )",
+       "diff-multi-sameuser": "(ಅದೇ ಬಳಕೆದಾರನ {{PLURAL:$1|ಮಧ್ಯದಲ್ಲಿನ ಬದಲಾವಣೆಯನ್ನು|$1 ಮಧ್ಯದ ಬದಲಾವಣೆಗಳನ್ನು}} ತೋರಿಸುತ್ತಿಲ್ಲ)",
        "searchresults": "ಶೋಧನೆಯ ಫಲಿತಾಂಶಗಳು",
        "searchresults-title": "\"$1\" ಅನ್ನು ಹುಡುಕಿದ ಫಲಿತಾಂಶಗಳು",
        "titlematches": "ಹೊಂದಿಕೆಯಿರುವ ಪುಟ ಶೀರ್ಷಿಕೆಗಳು",
        "shown-title": "ಪ್ರತಿ ಪುಟದಲ್ಲಿಯೂ $1 {{PLURAL:$1|result|results}} ತೋರಿಸು",
        "viewprevnext": "ವೀಕ್ಷಿಸು ($1 {{int:pipe-separator}} $2) ($3)",
        "searchmenu-exists": "'''\"[[:$1]]\" ಹೆಸರಿನ ಪುಟ ಈ ವಿಕಿಯಲ್ಲಿದೆ.'''",
-       "searchmenu-new": "'''''[[:$1]]'' ಪುಟವನ್ನು ಈ ವಿಕಿಯಲ್ಲಿ ಸೃಷ್ಟಿಸಿ!'''",
+       "searchmenu-new": "<strong>\"[[:$1]]\" ಪುಟವನ್ನು ಈ ವಿಕಿಯಲ್ಲಿ ಸೃಷ್ಟಿಸಿ!!</strong> {{PLURAL:$2|0=|See also the page found with your search.|See also the search results found.}}",
        "searchprofile-articles": "ಲೇಖನ ಪುಟ",
        "searchprofile-images": "ಮಲ್ಟಿಮೀಡಿಯ",
        "searchprofile-everything": "ಪ್ರತಿಯೊಂದು",
        "searchprofile-everything-tooltip": "ಎಲ್ಲಾ ಮಾಹಿತಿಗಳನ್ನು ಹುಡುಕಿ (ಚರ್ಚೆಯನ್ನೂ ಸೇರಿಸಿ)",
        "searchprofile-advanced-tooltip": "ಬಳಕೆಯ ನಾಮವರ್ಗಗಳಲ್ಲಿ ಹುಡುಕಿ",
        "search-result-size": "$1 ({{PLURAL:$2|೧ ಪದ|$2 ಪದಗಳು}})",
-       "search-redirect": "(ಪುನರ್ನಿರ್ದೇಶನ $1)",
+       "search-redirect": "($1 ಇಂದ ಪುನರ್ನಿರ್ದೇಶಿತ)",
        "search-section": "(ವಿಭಾಗ $1)",
        "search-suggest": "ನೀವು ಇದನ್ನು ಹುಡುಕುತ್ತಿರುವಿರೆ: $1",
        "search-interwiki-caption": "ಬಳಗದ ಇತರ ಯೋಜನೆಗಳು",
        "recentchanges-label-unpatrolled": "ಈ ಸಂಪಾದನೆಯನ್ನು ಇನ್ನೂ ಪರೀಕ್ಷೆಗೆ ಒಳಪಡಿಸಿಲ್ಲ",
        "recentchanges-label-plusminus": "ಪುಟದ ಗಾತ್ರವು ಇಷ್ಟು ಸಂಖ್ಯೆಯ ಬೈಟ್‍ಗಳಿಂದ ಬದಲಾಯಿಸಲ್ಪಟ್ಟಿದೆ",
        "recentchanges-legend-heading": "<strong>ಪರಿವಿಡಿ:</strong>",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|ಹೊಸ ಪುಟಗಳ ಪಟ್ಟಿ]]ಯನ್ನೂ ನೋಡಿ)",
        "rcnotefrom": "'''$2''' ಇಂದ ಆಗಿರುವ ಬದಲಾವಣೆಗಳು ಕೆಳಗಿವೆ (ಕೊನೆಯ '''$1'''ರವರೆಗೆ ತೋರಿಸಲಾಗಿದೆ).",
        "rclistfrom": "$3 $2 ಇಂದ ಪ್ರಾರಂಭಿಸಿ ಮಾಡಲಾದ ಬದಲಾವಣೆಗಳನ್ನು ನೋಡಿ",
        "rcshowhideminor": "ಚಿಕ್ಕಪುಟ್ಟ ಬದಲಾವಣೆಗಳನ್ನು $1",
        "deletereason-dropdown": "*ಸಾಮಾನ್ಯ ಅಳಿಸುವಿಕೆಯ ಕಾರಣಗಳು\n** ಸಂಪಾದಕರ ಕೋರಿಕೆ\n** ಕೃತಿಸ್ವಾಮ್ಯತೆಯ ಉಲ್ಲಂಘನೆ\n** Vandalism",
        "delete-edit-reasonlist": "ಅಳಿಸುವಿಕೆ ಕಾರಣಗಳನ್ನು ಸಂಪಾದಿಸು",
        "rollbacklink": "ತೊಡೆದುಹಾಕು",
+       "rollbacklinkcount": "$1 {{PLURAL:$1|ಸಂಪಾದನೆಯನ್ನು|ಸಂಪಾದನೆಗಳನ್ನು}} ತೊಡೆದುಹಾಕು",
        "changecontentmodel": "ಪುಟದ ವಿಷಯ ಮಾದರಿಯನ್ನು ಬದಲಾಯಿಸಿ",
        "changecontentmodel-legend": "ವಿಷಯ ಮಾದರಿಯನ್ನು ಬದಲಾಯಿಸಿ",
        "changecontentmodel-title-label": "ಪುಟ ಶೀರ್ಷಿಕೆ",
        "contributions": "{{GENDER:$1|User}} ಕಾಣಿಕೆಗಳು",
        "contributions-title": "$1 ಸದಸ್ಯರ ಕಾಣಿಕೆಗಳು",
        "mycontris": "ಕಾಣಿಕೆಗಳು",
+       "anoncontribs": "ಕಾಣಿಕೆಗಳು",
        "contribsub2": "$1 ($2) ಗೆ",
        "uctop": "(ಪ್ರಸಕ್ತ)",
        "month": "ಈ ತಿಂಗಳಿಂದ (ಮತ್ತು ಮುಂಚಿನ):",
        "whatlinkshere-next": "{{PLURAL:$1|ಮುಂದಿನ|ಮುಂದಿನ $1}}",
        "whatlinkshere-links": "← ಕೊಂಡಿಗಳು",
        "whatlinkshere-hideredirs": "$1 ಪುನರ್ನಿರ್ದೇಶನಗಳು",
-       "whatlinkshere-hidetrans": "$1 à²¸à³\87ರಿಸà³\81ವಿà²\95ೆಗಳು",
+       "whatlinkshere-hidetrans": "$1 à²¸à³\87ರà³\8dಪಡೆಗಳು",
        "whatlinkshere-hidelinks": "$1 ಕೊಂಡಿಗಳು",
        "whatlinkshere-hideimages": "$1 ಚಿತ್ರದ ಕೊಂಡಿಗಳು",
        "whatlinkshere-filters": "ಶೋಧಕಗಳು",
        "tooltip-pt-anonuserpage": "ನೀವು ಸಂಪಾದನೆ ಮಾಡುತ್ತಿರುವ ipಯ ಬಳಕೆದಾರ ಪುಟ",
        "tooltip-pt-mytalk": "ನಿಮ್ಮ ಚರ್ಚೆ ಪುಟ",
        "tooltip-pt-anontalk": "ಈ ip ವಿಳಾಸದಿಂದ ಮಾಡಲಾದ ಸಂಪಾದನೆಗಳ ಬಗ್ಗೆ ಚರ್ಚೆ",
-       "tooltip-pt-preferences": "ನನà³\8dನ ಆಯ್ಕೆಗಳು",
+       "tooltip-pt-preferences": "ನಿಮà³\8dಮ ಆಯ್ಕೆಗಳು",
        "tooltip-pt-watchlist": "ನೀವು ಬದಲಾವಣೆಗಳ ಮೇಲೆ ನಿಗಾ ವಹಿಸುತ್ತಿರುವ ಪುಟಗಳ ಪಟ್ಟಿ",
        "tooltip-pt-mycontris": "ನಿಮ್ಮ ಕಾಣಿಕೆಗಳ ಪಟ್ಟಿ",
        "tooltip-pt-login": "ನೀವು ಲಾಗ್ ಇನ್ ಆಗಬೇಕೆಂದು ಕೋರುತ್ತೇವೆ, ಆದರೆ ಅದು ಖಡ್ಡಾಯ ಎನೂ ಅಲ್ಲ.",
        "tooltip-t-recentchangeslinked": "ಈ ಪುಟದಿಂದ ಸಂಪರ್ಕ ಹೊಂದಿರುವ ಪುಟಗಳಲ್ಲಿನ ಇತ್ತೀಚಿನ ಬದಲಾವಣೆಗಳು",
        "tooltip-feed-rss": "ಈ ಪುಟಕ್ಕೆ RSS ಫೀಡು",
        "tooltip-feed-atom": "ಈ ಪುಟಕ್ಕೆ Atom ಫೀಡು",
-       "tooltip-t-contributions": "ಈ ಸದಸ್ಯರ ಕಾಣಿಕೆಗಳ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸು",
+       "tooltip-t-contributions": "{{GENDER:$1|ಈ ಸದಸ್ಯರ}} ಕಾಣಿಕೆಗಳ ಪಟ್ಟಿ",
        "tooltip-t-emailuser": "ಈ ಸದಸ್ಯರಿಗೆ ಇ-ಅಂಚೆಯನ್ನು ಕಳುಹಿಸು",
        "tooltip-t-upload": "ಫೈಲನ್ನು ಮೇಲಕ್ಕೆರಿಸಿ",
        "tooltip-t-specialpages": "ಎಲ್ಲಾ ವಿಶೇಷ ಪುಟಗಳ ಪಟ್ಟಿ",
        "exif-bitspersample": "ಪ್ರತಿ ಭಾಗಕ್ಕಿರುವ ಬಿಟ್‍ಗಳು",
        "exif-compression": "ಕುಗ್ಗಿಸಲು ಉಪಯೋಗಿಸಿರುವ ಪ್ರಕಾರ",
        "exif-photometricinterpretation": "ಚಿತ್ರಬಿಂದು ರಚನೆ",
+       "exif-orientation": "ದೃಷ್ಟಿಕೋನ",
        "exif-ycbcrpositioning": "Y ಮತ್ತು C ಸ್ಥಾನ",
        "exif-datetime": "ಫೈಲು ಬದಲಾದ ದಿನಾಂಕ ಮತ್ತು ಕಾಲ",
        "exif-imagedescription": "ಚಿತ್ರದ ಶೀರ್ಷಿಕೆ",
        "exif-artist": "ಕರ್ತೃ",
        "exif-copyright": "ಕೃತಿಸ್ವಾಮ್ಯತೆಯನ್ನು ಹೊಂದಿರುವವರು",
        "exif-exifversion": "Exif ಆವೃತ್ತಿ",
+       "exif-colorspace": "ರಂಗ ವಿಸ್ತಾರ",
        "exif-pixelxdimension": "ಭಾವಚಿತ್ರದ ಅಗಲ",
        "exif-pixelydimension": "ಭಾವಚಿತ್ರದ ಎತ್ತರ",
        "exif-usercomment": "ಬಳಕೆದಾರನ ಟಿಪ್ಪಣಿ",
        "revdelete-summary": "ಸಂಪಾದನೆಯ ತಾತ್ಪರ್ಯ",
        "feedback-message": "ಸಂದೇಶ:",
        "feedback-subject": "ವಿಷಯ:",
-       "searchsuggest-search": "ಹುಡುಕು",
+       "searchsuggest-search": "{{SITENAME}} ಅನ್ನು ಹುಡುಕಿ",
        "duration-seconds": "$1 {{PLURAL:$1|ಕ್ಷಣ|ಕ್ಷಣಗಳು}}",
        "duration-minutes": "$1 {{PLURAL:$1|ನಿಮಿಷ|ನಿಮಿಷಗಳು}}",
        "duration-hours": "$1 {{PLURAL:$1|ಘಂಟೆ|ಘಂಟೆಗಳು}}",
index 1dc2caf..2456c91 100644 (file)
        "prefs-personal": "사용자 정보",
        "prefs-rc": "최근 바뀜",
        "prefs-watchlist": "주시문서 목록",
-       "prefs-editwatchlist": "주시목록 편집",
+       "prefs-editwatchlist": "주ì\8b\9c문ì\84\9c ëª©ë¡\9d í\8e¸ì§\91",
        "prefs-editwatchlist-label": "주시문서 목록의 항목을 편집합니다:",
        "prefs-editwatchlist-edit": "주시문서의 제목을 보고 지우기",
        "prefs-editwatchlist-raw": "주시문서 목록 직접 편집하기",
        "feedback-thanks": "감사합니다! \"[$2 $1]\" 문서에 의견을 남겼습니다.",
        "feedback-thanks-title": "감사합니다!",
        "feedback-useragent": "사용자 에이전트:",
-       "searchsuggest-search": "검색",
+       "searchsuggest-search": "{{SITENAME}} 검색",
        "searchsuggest-containing": "다음 문자열 포함...",
        "api-error-autoblocked": "사용자의 IP 주소는 차단된 사용자에 의해 사용되었으므로 자동으로 차단된 상태입니다.",
        "api-error-badaccess-groups": "이 위키에 파일을 올릴 권한이 없습니다.",
        "usercssispublic": "주목해 주십시오: CSS의 하위 문서들은 다른 사용자들이 볼 수 있기 때문에 기밀 데이터를 포함해서는 안 됩니다.",
        "restrictionsfield-badip": "유효하지 않은 IP 주소나 대역: $1",
        "restrictionsfield-label": "허용된 IP 대역:",
-       "restrictionsfield-help": "줄 단위의 하나의 IP 주소 또는 CIDR 대역입니다. 모든 곳에 적용하려면, 다음을 사용하세요<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "줄 단위의 하나의 IP 주소 또는 CIDR 대역입니다. 모든 곳에 적용하려면, 다음을 사용하세요<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "오류: $1",
+       "edit-error-long": "오류:\n\n$1"
 }
index 76f1cce..ec6d6a2 100644 (file)
        "feedback-thanks": "Merci! Äre Feedback gouf op der Säit \"[$2 $1]\" gespäichert.",
        "feedback-thanks-title": "Merci!",
        "feedback-useragent": "User Agent:",
-       "searchsuggest-search": "Sichen",
+       "searchsuggest-search": "Op {{SITENAME}} sichen",
        "searchsuggest-containing": "mat ...",
        "api-error-autoblocked": "Är IP-Adress gouf automatesch gespaart wëll se vun engem gespaarte Benotzer  benotzt gouf",
        "api-error-badaccess-groups": "Et ass Iech net erlaabt fir Fichieren op dës Wiki eropzelueden.",
        "linkaccounts-submit": "Benotzerkonte verbannen",
        "userjsispublic": "DEnkt drun: Op JavaScript-Ënnersäite solle keng vertraulech Informatioune stoe well se vun anere Benotzer kënne gesi ginn.",
        "restrictionsfield-badip": "Net valabel IP-Adress oder Beräich: $1",
-       "restrictionsfield-label": "Zougeloossen IP-Beräicher:"
+       "restrictionsfield-label": "Zougeloossen IP-Beräicher:",
+       "edit-error-short": "Feeler: $1",
+       "edit-error-long": "Feeler:\n\n$1"
 }
index c9f6091..4fec1a2 100644 (file)
@@ -33,8 +33,8 @@
        "tog-watchuploads": "Azonzi i noeuvi file che metto in osservaçion",
        "tog-watchrollback": "Azonzi a-i sotta osservassion e paggine dovve ho fæto un rollback",
        "tog-minordefault": "Indica de longo comme menô e modiffiche",
-       "tog-previewontop": "Veddi l'anteprimma de d'äto a-o spaçio pe cangiâ",
-       "tog-previewonfirst": "Veddi l'anteprimma a-o primmo cangiamento",
+       "tog-previewontop": "Mostra l'anteprimma de d'ato a-a casella de modiffica",
+       "tog-previewonfirst": "Mostra l'anteprimma in sciâ primma modiffica",
        "tog-enotifwatchlistpages": "Famme savéi via e-mail quande 'na paggina o in file inti mæ osservæ a ven cangiâ.",
        "tog-enotifusertalkpages": "Màndime un'e-mail se gh'é de modìffiche inta mæ pagina de discuscion.",
        "tog-enotifminoredits": "Mandime una email ascì pe e modifiche menoî de pagine e di file",
        "noindex-category": "Paggine sença endexo",
        "broken-file-category": "Paggine con di colegamenti a di file che no ghe son",
        "about": "Informaçioìn",
-       "article": "Pagina di contegnùi",
+       "article": "Voxe",
        "newwindow": "(O s'arve inte 'n âtro barcon)",
        "cancel": "Scancella",
        "moredotdotdot": "De ciû...",
        "largefileserver": "O file o suppera e dimenscioin consentie da-a configuaçion do server.",
        "emptyfile": "O file apen-a caregou pâ esee voeuo. Questo poriæ ese dovuo a un aro into nomme do file. Controlla se ti voeu davei caregâ sto file.",
        "windows-nonascii-filename": "Questo wiki o no supporta di nommi de file con di caratteri speciali.",
-       "fileexists": "Un papê con sto nomme o l'existe za, pe piaxei danni 'n'euggiâ a <strong>[[:$1]]</strong> se no ti t'ê seguo de voeilo cangiâ.\n[[$1|thumb]]",
+       "fileexists": "Un file con sto nomme o l'existe za, pe piaxei danni 'n'oeuggiâ a <strong>[[:$1]]</strong> se no ti t'ê seguo de voeilo cangiâ.\n[[$1|thumb]]",
        "filepageexists": "A pagina de descriçion de questo file a l'è za stæta creâ a l'adreçço <strong>[[:$1]]</strong>, sciben che no ghe segge ancon un file con questo nomme. A descriçion de l'oggetto inseia in fase de caregamento a no l'appariâ in scia pagina de descriçion. Pe fâ scì che l'oggetto o comparisce in sciâ pagina de descriçion, saiâ necessaio modificala manualmente.\n[[$1|thumb]]",
        "fileexists-extension": "Un file co-in nomme scimile a questo o l'esiste za: [[$2|thumb]]\n* Nomme do file caregou: <strong>[[:$1]]</strong>\n* Nomme do file existente: <strong>[[:$2]]</strong>\nTi voeu miga çerne un nomme ciu caratteristego?",
-       "fileexists-thumbnail-yes": "O file caregou o pâ ese una miniatua ''(thumbnail)''. [[$1|thumb]]\nVerifica, pe confronto, il file <strong>[[:$1]]</strong>.\nSe se tratta da mæxima inmaggine, inte dimenscioin originale, no l'è necessaio caregâne un'atra in miniatua.",
+       "fileexists-thumbnail-yes": "O file caregou o pâ ese 'na miniatua ''(thumbnail)''. [[$1|thumb]]\nControlla o file <strong>[[:$1]]</strong>.\nSe se tratta da mæxima inmaggine, inte dimenscioin originale, no l'è necessaio caregâne un'atra in miniatua.",
        "file-thumbnail-no": "O nomme do file comença con <strong>$1</strong>; pâ ch'o segge un'inmaggine de dimenscioin redute ''(miniatua)''.\nSe ti dispon-i del'immaggine inta risoluçion originale, carreghila. Sedunque, pe piaxei, cangighe o nomme.",
        "fileexists-forbidden": "Un file con questo nomme o l'existe za e o no poeu ese soviascrito. Se ti voeu caregâ o to file, torna inderê e dagghe un atro nomme. [[File:$1|thumb|center|$1]]",
        "fileexists-shared-forbidden": "Un file con questo nomme o l'esiste za inte l'archivio de risorse multimediæ condivise. Se ti dexiddei ancon caregâ o file, torna inderê e modifica o nomme co-o quæ caregâ o file. [[File:$1|thumb|center|$1]]",
        "undeletepage": "Veddi e recuppera e pagine scançellæ",
        "undeletepagetitle": "'''Quanto segue o l'è composto da de revixoin scassæ de [[:$1|$1]]'''.",
        "viewdeletedpage": "Veddi e paggine scassæ",
-       "undeletepagetext": "{{PLURAL:$1|A seguente pagina a l'è stæta scassâ, ma a l'è ancon in archivio e pertanto a poeu ese recuperâ|Le seguente pagine son stæte scassæ, ma son ancon in archivio e pertanto poeuan ese recuperæ}}. L'archivio o poeu ese vuou periodicamente.",
+       "undeletepagetext": "{{PLURAL:$1|A seguente pagina a l'è stæta scassâ, ma a l'è ancon in archivio e pertanto a poeu ese recuperâ|E seguente pagine son stæte scassæ, ma son ancon in archivio e pertanto poeuan ese recuperæ}}. L'archivio o poeu ese vuou periodicamente.",
        "undelete-fieldset-title": "Ripristina revixoin",
        "undeleteextrahelp": "Pe recuperâ l'intrega cronologia da pagina, lascia tutte e caselle deseleçionæ e fanni clic insce '''''{{int:undeletebtn}}'''''.\nPe effettuâ un ripristino selettivo, seleçion-a e caselle corrispondente a-e verscioin da ripristinâ e fanni clic insce '''''{{int:undeletebtn}}'''''.",
        "undeleterevisions": "{{PLURAL:$1|Una revixon scassâ|$1 revixoin scassæ}}",
        "movepagetalktext": "Se ti seleçion-i questa casella, a corispondente paggina de discuscion a saiâ mesciâ aotomaticamente a-o neuvo tittolo, a meno che existe zà una paggina de discuscion ch'a no segge veua.\n\nInte sti caxi, ti doviæ mesciâ o unî manoalmente a paggina, se proppio ti veu.",
        "moveuserpage-warning": "'''Attençione:''' Ti stæ pe mesciâ una pagina utente. Notta che solo a pagina a saiâ mesciâ. L'utente o ''no'' saiâ rinominou.",
        "movecategorypage-warning": "<strong>Attençione:</strong> ti stæ pe mesciâ una categoria. Notta che solo sta paggina a saiâ mesciâ e tutte e pagine inta vegia categoria <em>no</em> saian inseie inta noeuva.",
-       "movenologintext": "O stramuo dee paggine o l'è consentio solo che a-i utenti registræ ch'han eseguio l'[[Special:UserLogin|accesso]] a-o scito.",
+       "movenologintext": "O stramuo de paggine o l'è consentio solo che a-i utenti registræ ch'han eseguio l'[[Special:UserLogin|accesso]] a-o scito.",
        "movenotallowed": "No ti g'hæ o permisso pe mesciâ de paggine.",
        "movenotallowedfile": "No ti g'hæ o permisso pe mesciâ di file.",
        "cant-move-user-page": "No ti g'hæ o permisso pe mesciâ de pagine utente (escluse e sottopagine).",
        "allmessagesdefault": "Testo predefinio",
        "allmessagescurrent": "Testo corrente",
        "allmessagestext": "Sta chie a l'è a lista de tutti i messaggi de scistema disponibili into namespace MediaWiki.\nVixita [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] e [https://translatewiki.net translatewiki.net] se ti voeu contribuî a-a localizzaçion generrica de MediaWiki.",
-       "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' o non ti te peu vedde, perchè '''$wgUseDatabaseMessages''' o non l'è attivo.",
+       "allmessagesnotsupportedDB": "No l'è poscibbile doeuviâ sta paggina perchè o flag '''$wgUseDatabaseMessages''' o no l'è attivo.",
        "allmessages-filter-legend": "Filtro",
        "allmessages-filter": "Filtra pe stato de modiffica:",
        "allmessages-filter-unmodified": "Non modificæ",
        "tooltip-undo": "\"Anùlla\" o permette de anulâ sto cangiaménto e o l'arve o modulo de cangiaménto inta modalitæ anteprìmma. Ti peu ascì métte a raxón inte l'ogetto do cangiaménto.",
        "tooltip-preferences-save": "Sarva e preferençe",
        "tooltip-summary": "Scrîvi 'na scintexi",
-       "common.css": "/** i stili css scriti chie se applicana tutte e skin */",
+       "common.css": "/** i stili css scriti chì se apprican a tutte e skin */",
        "anonymous": "{{PLURAL:$1|Utente anonnimo|Utenti anonnimi}} de {{SITENAME}}",
        "siteuser": "$1, utente de {{SITENAME}}",
        "anonuser": "$1, utente anonnimo de {{SITENAME}}",
        "limitreport-expansiondepth": "Mascima profonditæ d'espanscion",
        "limitreport-expensivefunctioncount": "Nummero de fonçioin do parser dispendiose",
        "expandtemplates": "Espanscion di template",
-       "expand_templates_intro": "Questa pagina speciale a l'elabboa un testo espandendo tutti i template presenti.\nA carcoa ascì o risultou de fonçioon supportæ da-o parser comme\n<code><nowiki>{{</nowiki>#language:…}}</code> e de variabbile de scistema quæ\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>,\nsaiv'a dî inta prattica tutto 'lo che s'attroeuva tra parentexi graffe dogge.",
+       "expand_templates_intro": "Questa pagina speciale a l'elabboa un scrito espandendo tutti i template presenti.\nA calcola ascì o risultato de fonçioin supportæ da-o parser comme\n<code><nowiki>{{</nowiki>#language:…}}</code> e de variabbile de scistema quæ\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>,\nsaiv'a dî inta prattica tutto 'lo che s'attroeuva tra parentexi graffe dogge.",
        "expand_templates_title": "Contesto (pe {{FULLPAGENAME}} eçç.):",
        "expand_templates_input": "Testo da espande:",
        "expand_templates_output": "Risultou",
index e152c76..5998caf 100644 (file)
        "tog-hidepatrolled": "Slėpti patikrintus keitimus paskutinių keitimų sąraše",
        "tog-newpageshidepatrolled": "Slėpti patikrintus puslapius iš naujausių straipsnių sąrašo",
        "tog-hidecategorization": "Slėpti puslapių kategorizavimą",
-       "tog-extendwatchlist": "Išplėsti stebimųjų sąrašą, kad rodytų visus tinkamus keitimus, ne tik pačius naujausius.",
+       "tog-extendwatchlist": "Išplėsti stebimųjų sąrašą, kad rodytų visus tinkamus keitimus, ne tik pačius naujausius",
        "tog-usenewrc": "Grupuoti pakeitimas pagal puslapį paskutinių keitimų ir stebėjimo sąrašuose",
        "tog-numberheadings": "Automatiškai numeruoti skyrelius",
        "tog-showtoolbar": "Rodyti redagavimo įrankių juosta",
        "tog-editondblclick": "Puslapių redagavimas dvigubu spustelėjimu (JavaScript)",
        "tog-editsectiononrightclick": "Įjungti skyrelių redagavimą paspaudus skyrelio pavadinimą dešiniuoju pelės klavišu (JavaScript)",
-       "tog-watchcreations": "Pridėti puslapius, kuriuos aš sukuriu, į stebimų sąrašą",
-       "tog-watchdefault": "Pridėti puslapius, kuriuos aš redaguoju, į stebimų sąrašą",
-       "tog-watchmoves": "Pridėti puslapius, kuriuos aš perkeliu, į stebimų sąrašą",
-       "tog-watchdeletion": "Pridėti puslapius, kuriuos aš ištrinu, į stebimų sąrašą",
+       "tog-watchcreations": "Pridėti mano sukuriamus puslapius į stebimųjų sąrašą",
+       "tog-watchdefault": "Pridėti puslapius, kuriuos aš redaguoju, į stebimų sąrašą",
+       "tog-watchmoves": "Pridėti puslapius ir failus, kuriuos aš perkeliu, į stebimųjų sąrašą",
+       "tog-watchdeletion": "Pridėti puslapius, kuriuos aš ištrinu, į stebimų sąrašą",
        "tog-watchuploads": "Pridėti naujus failus, kurios aš įkeliu, į mano stebimųjų sąrašą",
-       "tog-watchrollback": "Pridėti puslapius, kuriuose aš atlikau atmetimus į mano stebėjimo sąrašą",
+       "tog-watchrollback": "Pridėti puslapius, kuriuose aš atlikau atmetimus, į stebimųjų sąrašą",
        "tog-minordefault": "Pagal nutylėjimą pažymėti redagavimus kaip smulkius",
        "tog-previewontop": "Rodyti peržiūrą virš redagavimo lauko",
        "tog-previewonfirst": "Rodyti peržiūrą pirmą kartą pakeitus",
        "tog-enotifminoredits": "Siųsti man laišką, kai puslapio keitimas yra smulkus",
        "tog-enotifrevealaddr": "Rodyti mano el. pašto adresą priminimo laiškuose",
        "tog-shownumberswatching": "Rodyti stebinčių naudotojų skaičių",
-       "tog-oldsig": "Jūsų egzistuojantis parašas:",
+       "tog-oldsig": "Jūsų dabartinis parašas:",
        "tog-fancysig": "Laikyti parašą vikitekstu (be automatinių nuorodų)",
        "tog-uselivepreview": "Naudoti tiesioginę peržiūrą",
        "tog-forceeditsummary": "Klausti, kai palieku tuščią keitimo komentarą",
-       "tog-watchlisthideown": "Slėpti mano keitimus stebimų sąraše",
-       "tog-watchlisthidebots": "Slėpti robotų keitimus stebimų sąraše",
-       "tog-watchlisthideminor": "Slėpti smulkius keitimus stebimų sąraše",
+       "tog-watchlisthideown": "Slėpti mano keitimus stebimų sąraše",
+       "tog-watchlisthidebots": "Slėpti botų keitimus stebimųjų sąraše",
+       "tog-watchlisthideminor": "Slėpti smulkius keitimus stebimų sąraše",
        "tog-watchlisthideliu": "Slėpti prisijungusių naudotojų keitimus stebimųjų sąraše",
        "tog-watchlistreloadautomatically": "Atnaujinti stebėjimų sąrašą automatiškai, kai tik filtras yra pakeičiamas (reikalingas JavaScript)",
        "tog-watchlisthideanons": "Slėpti anoniminių naudotojų keitimus stebimųjų sąraše",
        "laggedslavemode": "Dėmesio: Puslapyje gali nesimatyti naujausių pakeitimų.",
        "readonly": "Duomenų bazė užrakinta",
        "enterlockreason": "Įveskite užrakinimo priežastį, taip pat datą, kada bus atrakinta",
-       "readonlytext": "Duomenų bazė šiuo metu yra užrakinta naujiems įrašams ar kitiems keitimams,\nturbūt duomenų bazės techninei profilaktikai,\npo to viskas vėl veiks kaip įprasta.\n\nUžrakinusiojo administratoriaus pateiktas rakinimo paaiškinimas: $1",
+       "readonlytext": "Duomenų bazė šiuo metu yra užrakinta naujiems įrašams ar kitiems keitimams,greičiausiai duomenų bazės techninei profilaktikai,\npo kurios viskas vėl veiks kaip įprasta.\n\nUžrakinusiojo sistemos administratoriaus pateiktas paaiškinimas: $1",
        "missing-article": "Duomenų bazė nerado puslapio teksto, kurį ji turėtų rasti, pavadinto „$1“ $2.\n\nPaprastai tai būna dėl pasenusios skirtumo ar istorijos nuorodos į puslapį, kuris buvo ištrintas.\n\nJei tai ne tas atvejis, jūs galbūt radote klaidą programinėje įrangoje.\nPrašome apie tai pranešti [[Special:ListUsers/sysop|administratoriui]], nepamiršdami nurodyti nuorodą.",
        "missingarticle-rev": "(versija#: $1)",
        "missingarticle-diff": "(Skirt.: $1, $2)",
        "title-invalid-magic-tilde": "Prašomo puslapio pavadinimas turi negalima magiška tildės seką (<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "Prašomo puslapio pavadinimas yra per ilgas. Jis turi būti ne ilgesnis nei {{PLURAL:$1|baitas|baitai}} UTF-8 koduotėje.",
        "title-invalid-leading-colon": "Prašomo puslapio pavadinimas turi neleistiną dvitaškį pradžioje.",
-       "perfcached": "Rodoma išsaugota duomenų kopija, todėl duomenys gali būti ne patys naujausi. Maksimaliai $1 {{PLURAL:$1|rezultatas|rezultatai|rezultatų}} yra saugoma.",
-       "perfcachedts": "Rodoma išsaugota duomenų kopija, kuri buvo atnaujinta $2 $3. Maksimaliai $4 {{PLURAL:$4|rezultatas|rezultatai|rezultatų}} yra saugoma.",
+       "perfcached": "Rodoma išsaugota duomenų kopija, todėl duomenys gali būti ne patys naujausi. Saugoma iki $1 {{PLURAL:$1|rezultatas|rezultatai|rezultatų}}.",
+       "perfcachedts": "Rodoma išsaugota duomenų kopija, kuri buvo atnaujinta $2 $3. Saugoma iki $4 {{PLURAL:$4|rezultatas|rezultatai|rezultatų}}.",
        "querypage-no-updates": "Atnaujinimai šiam puslapiui dabar yra išjungti. Duomenys čia dabar nebus atnaujinti.",
        "viewsource": "Žiūrėti kodą",
        "viewsource-title": "Peržiūrėti šaltinį $1",
        "actionthrottled": "Veiksmas apribotas",
-       "actionthrottledtext": "Kad būtų apsisaugota nuo reklamų, jums neleidžiama daug kartų atlikti šį veiksmą per trumpą laiko tarpą, bet jūs pasiekėte šį limitą. Prašome vėl pamėginti po kelių minučių.",
+       "actionthrottledtext": "Kad būtų apsisaugota nuo pažeidimų, jums neleidžiama pernelyg daug kartų atlikti šį veiksmą per trumpą laiko tarpą. Jūs viršijote šį limitą. Prašome vėl pamėginti po kelių minučių.",
        "protectedpagetext": "Šis puslapis yra užrakintas, saugant jį nuo redagavimo.",
        "viewsourcetext": "Jūs galite peržiūrėti ir kopijuoti puslapio kodą:",
        "viewyourtext": "Jūs galite peržiūrėti ir kopijuoti <strong>savo pakeitimų</strong> kodą į šį puslapį:",
        "eauthentsent": "Patvirtinimo laiškas buvo nusiųstas į paskirtąjį el. pašto adresą.\nPrieš išsiunčiant kitą laišką į jūsų dėžutę, jūs turite vykdyti nurodymus laiške, kad patvirtintumėte, kad dėžutė tikrai yra jūsų.",
        "throttled-mailpassword": "Slaptažodžio priminimas jau buvo išsiųstas, per {{PLURAL:$1|$1 paskutinę valandą|$1 paskutines valandas|$1 paskutinių valandų}}.\n\nNorint apsisaugoti nuo piktnaudžiavimo, slaptažodžio priminimas gali būti išsiųstas tik kas {{PLURAL:$1|$1 valandą|$1 valandas|$1 valandų}}.",
        "mailerror": "Klaida siunčiant laišką: $1",
-       "acct_creation_throttle_hit": "Šio projekto lankytojai, naudojantys jūsų IP adresą, sukūrė {{PLURAL:$1|$1 paskyrą|$1 paskyras|$1 paskyrų}} per paskutiniąją dieną, o tai yra didžiausias leidžiamas kiekis per šį laiko tarpą.\nTodėl šiuo metu lankytojai, naudojantys šį IP adresą, daugiau negali kurti paskyrų.",
+       "acct_creation_throttle_hit": "Šio projekto lankytojai, naudojantys jūsų IP adresą, sukūrė {{PLURAL:$1|$1 paskyrą|$1 paskyras|$1 paskyrų}} per $2, o tai yra didžiausias leidžiamas kiekis per šį laiko tarpą.\nTodėl šiuo metu lankytojai, naudojantys šį IP adresą, daugiau negali kurti paskyrų.",
        "emailauthenticated": "Jūsų el. pašto adresas buvo patvirtintas $2 d. $3.",
        "emailnotauthenticated": "Jūsų el. pašto adresas dar nėra patvirtintas. Jokie laiškai\nnebus siunčiami nei vienai žemiau išvardintai paslaugai.",
        "noemailprefs": "Nurodykite el. pašto adresą, kad šios funkcijos veiktų.",
        "pt-userlogout": "Atsijungti",
        "php-mail-error-unknown": "Nežinoma klaida PHP mail() funkcijoje",
        "user-mail-no-addy": "Bandyta išsiųsti elektroninį laišką be el. pašto adreso.",
-       "user-mail-no-body": "Mėginta siųsti tuščia ar pernelyg trumpą E-pašto žinutė.",
+       "user-mail-no-body": "Bandyta siųsti tuščią ar pernelyg trumpą el. pašto žinutę.",
        "changepassword": "Pakeisti slaptažodį",
        "resetpass_announce": "Norint užbaigti prisijungimą jums reikia nustatyti naująjį slaptažodį.",
        "resetpass_text": "<!-- Įterpkite čia tekstą -->",
        "resetpass-expired": "Jūsų slaptažodžio galiojimas baigėsi. Prašome nustatyti naują prisijungimo slaptažodį.",
        "resetpass-expired-soft": "Jūsų slaptažodžio galiojimas baigėsi ir jį reikia atkurti iš naujo. Pasirinkite naują slaptažodį dabar arba spauskite \"{{int:authprovider-resetpass-skip-label}}\", kad būtų atstatytas vėliau.",
        "resetpass-validity-soft": "Jūsų slaptažodis netinkamas: $1\n\nPasirinkite naują slaptažodį dabar arba spauskite \"{{int:authprovider-resetpass-skip-label}}\", kad būtų atkurtas vėliau.",
-       "passwordreset": "Atstatyti slaptažodį",
+       "passwordreset": "Atkurti slaptažodį",
        "passwordreset-text-one": "Užpildykite šią formą, norėdami atkurti savo slaptažodį.",
-       "passwordreset-text-many": "{{PLURAL:$1|Užpildykite vieną iš laukų slaptažodžio atkūrimui.}}",
+       "passwordreset-text-many": "{{PLURAL:$1|Užpildykite vieną iš laukelių, kad el. paštu gautumėte laikinąjį slaptažodį.}}",
        "passwordreset-disabled": "Slaptažodžių atstatymai šiame wikyje išjungti.",
        "passwordreset-emaildisabled": "El. pašto funkcijos uždraustos šiame wiki.",
        "passwordreset-username": "Naudotojo vardas:",
        "subject-preview": "Temos peržiūra:",
        "previewerrortext": "Įvyko klaida bandant peržiūrėti jūsų pakeitimus.",
        "blockedtitle": "Naudotojas yra užblokuotas",
-       "blockedtext": "'''Jūsų naudotojo vardas arba IP adresas yra užblokuotas.'''\n\nUžblokavo $1. Nurodyta priežastis yra ''$2''.\n\n* Blokavimo pradžia: $8\n* Blokavimo pabaiga: $6\n* Numatytas blokuojamasis: $7\n\nJūs galite susisiekti su $1 arba kuriuo nors kitu [[{{MediaWiki:Grouppage-sysop}}|administratoriumi]] ir aptarti neaiškumus dėl blokavimo.\nAtkreipkite dėmesį, kad negalėsite naudotis funkcija „Rašyti laišką šiam naudotojui“, jei nesate užsiregistravę ir pateikę realaus savo el. pašto adreso naudotojo [[Special:Preferences|nustatymuose]], arba, jei jums užblokuotas šios funkcijos naudojimas.\nJūsų IP adresas yra $3, o blokavimo ID yra #$5.\nPrašome nurodyti vieną iš jų ar abu, kai kreipiatės dėl blokavimo.",
+       "blockedtext": "'''Jūsų naudotojo vardas arba IP adresas yra užblokuotas.'''\n\nUžblokavo $1. Nurodyta priežastis yra ''$2''.\n\n* Blokavimo pradžia: $8\n* Blokavimo pabaiga: $6\n* Užblokuotasis: $7\n\nJūs galite susisiekti su $1 arba kuriuo nors kitu [[{{MediaWiki:Grouppage-sysop}}|administratoriumi]] ir aptarti neaiškumus dėl blokavimo.\nAtkreipkite dėmesį, kad negalėsite naudotis funkcija „Rašyti laišką šiam naudotojui“, jei nesate užsiregistravę ir pateikę galiojančio el. pašto adreso naudotojo paskyros [[Special:Preferences|nustatymuose]], arba, jei jums užblokuotas šios funkcijos naudojimas.\nJūsų IP adresas yra $3, o blokavimo ID yra #$5.\nPrašome nurodyti vieną iš jų ar abu, kai kreipiatės dėl blokavimo.",
        "autoblockedtext": "Jūsų IP adresas buvo automatiškai užblokuotas, nes jį naudojo kitas naudotojas, kurį užblokavo $1.\nNurodyta priežastis yra ši:\n\n:''$2''\n\n* Blokavimo pradžia: $8\n* Blokavimo pabaiga: $6\n* Numatomas blokavimo laikas: $7\n\nJūs galite susisiekti su $1 arba kitu [[{{MediaWiki:Grouppage-sysop}}|administratoriumi]], kad aptartumėte neaiškumus dėl blokavimo.\n\nJūs negalite naudotis funkcija „Rašyti laišką šiam naudotojui“, jei nesate nurodę tikro el. pašto adreso savo [[Special:Preferences|naudotojo nustatymuose]]. Taip pat Jūs negalite naudotis šia funkcija, jei Jums užblokuotas jos naudojimas.\n\nJūsų IP adresas yra $3, blokavimo ID yra $5.\nPrašome nurodyti šiuos duomenis visais atvejais, kai kreipiatės dėl blokavimo.",
        "blockednoreason": "priežastis nenurodyta",
        "whitelistedittext": "Jūs turite $1, kad redaguotumėte puslapius.",
        "newarticletext": "Jūs patekote į dar neegzistuojantį puslapį.\nNorėdami sukurti puslapį, pradėkite rašyti žemiau esančiame įvedimo lauke\n(plačiau [$1 pagalbos puslapyje]).\nJei patekote čia per klaidą, paprasčiausiai spustelkite  naršyklės mygtuką '''atgal'''.",
        "anontalkpagetext": "----''Tai yra anoniminio naudotojo, nesusikūrusio arba nenaudojančio paskyros, aptarimų puslapis.\nDėl to naudojamas IP adresas jo identifikavimui.\nŠis IP adresas gali būti dalinamas keliems naudotojams.\nJeigu Jūs esate anoniminis naudotojas ir atrodo, kad komentarai nėra skirti Jums, [[Special:CreateAccount|sukurkite paskyrą]] arba [[Special:UserLogin|prisijunkite]], ir nebūsite tapatinamas su kitais anoniminiais naudotojais.''",
        "noarticletext": "Šiuo metu šiame puslapyje nėra jokio teksto.\nJūs galite [[Special:Search/{{PAGENAME}}|ieškoti šio puslapio pavadinimo]] kituose puslapiuose,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ieškoti susijusių įrašų] arba [{{fullurl:{{FULLPAGENAME}}|action=edit}} sukurti šį puslapį]</span>.",
-       "noarticletext-nopermission": "Šiuo metu šiame puslapyje nėra jokio teksto.\nJūs galite [[Special:Search/{{PAGENAME}}|ieškoti šio puslapio pavadinimo]] kituose puslapiuose,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ieškoti susijusių įrašų]</span>, bet jūs neturite teisės sukurti šį puslapį.",
+       "noarticletext-nopermission": "Šiuo metu šiame puslapyje nėra jokio teksto.\nJūs galite [[Special:Search/{{PAGENAME}}|ieškoti šio puslapio pavadinimo]] kituose puslapiuose,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} ieškoti susijusių įrašų]</span>, tačiau jūs neturite teisės sukurti šio puslapio.",
        "missing-revision": "Puslapio peržiūra #$1 pavadinto „{{FULLPAGENAME}}“ neegzistuoja.\n\nTai paprastai atsitinka kai pasenusi nuoroda veda į puslapį, kuris buvo ištrintas.\nInformaciją galima rasti [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} deletion log].",
        "userpage-userdoesnotexist": "Naudotojo paskyra „<nowiki>$1</nowiki>“ yra neužregistruota. Prašom patikrinti, ar jūs norite kurti/redaguoti šį puslapį.",
        "userpage-userdoesnotexist-view": "Naudotojo paskyra „$1“ neužregistruota.",
        "suppressionlog": "Trynimo sąrašas",
        "suppressionlogtext": "Žemiau yra trynimų ir blokavimų sąrašas, įtraukiant turinį, paslėptą nuo administratorių.\nŽiūrėkite [[Special:BlockList|blokavimų sąrašą]], kad rastumėte dabar veikiančius draudimus ir blokavimus.",
        "mergehistory": "Sujungti puslapių istorijas",
-       "mergehistory-header": "Šis puslapis leidžia jus prijungti vieno pirminio puslapio istorijos versijas į naujesnį puslapį. Įsitikinkite, kad šis pakeitimas palaikys istorinį puslapio tęstinumą.\n\n'''Turi likti bent dabartinė pirminio puslapio versija.'''",
+       "mergehistory-header": "Šis puslapis leidžia jums prijungti vieno pirminio puslapio istorijos versijas į naujesnį puslapį. Įsitikinkite, kad šis pakeitimas palaikys istorinį puslapio tęstinumą.\n\n'''Turi likti bent dabartinė pirminio puslapio versija.'''",
        "mergehistory-box": "Sujungti dviejų puslapių versijas:",
        "mergehistory-from": "Pirminis puslapis:",
        "mergehistory-into": "Paskirties puslapis:",
        "searchprofile-advanced-tooltip": "Ieškoti skirtingose vardų srityse",
        "search-result-size": "$1 ({{PLURAL:$2|1 žodis|$2 žodžiai|$2 žodžių}})",
        "search-result-category-size": "{{PLURAL:$1|1 narys|$1 narių}} ({{PLURAL:$2|1 subkategorijoje|$2 subkategorijų}}, {{PLURAL:$3|1 failas|$3 failų}})",
-       "search-redirect": "(peradresavimas $1)",
+       "search-redirect": "(peradresavimas iš $1)",
        "search-section": "(skyrius $1)",
        "search-category": "(kategorija $1)",
        "search-file-match": "(atitinka rinkmenos turinį)",
        "prefs-user-pages": "Naudotojo puslapiai",
        "prefs-personal": "Naudotojo profilis",
        "prefs-rc": "Naujausi keitimai",
-       "prefs-watchlist": "Stebimų sąrašas",
+       "prefs-watchlist": "Stebimų sąrašas",
        "prefs-editwatchlist": "Redaguoti stebimųjų sąrašą",
-       "prefs-editwatchlist-label": "Redaguoti įrašus savo stebėjimo sąraše:",
-       "prefs-editwatchlist-edit": "Peržiūrėti ir pašalinti pavadinmus savo stebėjimo sąraše",
+       "prefs-editwatchlist-label": "Redaguoti įrašus stebėjimųjų sąraše:",
+       "prefs-editwatchlist-edit": "Peržiūrėti ir pašalinti puslapius iš stebimųjų sąrašo",
        "prefs-editwatchlist-raw": "Redaguoti grynąjį stebimųjų sąrašą",
        "prefs-editwatchlist-clear": "Išvalyti stebimųjų sąrašą",
        "prefs-watchlist-days": "Dienos rodomos stebimųjų sąraše:",
        "timezoneregion-europe": "Europa",
        "timezoneregion-indian": "Indijos vandenynas",
        "timezoneregion-pacific": "Ramusis vandenynas",
-       "allowemail": "Leisti siųsti el. laiškus iš kitų naudotojų",
+       "allowemail": "Leisti kitiems naudotojams siųsti man el. laiškus",
        "prefs-searchoptions": "Paieška",
        "prefs-namespaces": "Vardų sritys",
        "default": "pagal nutylėjimą",
        "email": "El. paštas",
        "prefs-help-realname": "Tikrasis vardas yra neprivalomas.\nJei jūs jį įvesite, jis bus naudojamas pažymėti jūsų darbą.",
        "prefs-help-email": "E-pašto adresas yra neprivalomas, tačiau reikalingas slaptažodį naujo, turi tu pamiršai savo slaptažodį.",
-       "prefs-help-email-others": "Taip pat galite pasirinkti, kad žmonės galėtų susisiekti su jumis per jūsų naudotojo ar naudotojo aptarimo puslapį neatskleidžiant jūsų tapatybės.",
+       "prefs-help-email-others": "Taip pat galite pasirinkti, kad žmonės galėtų susisiekti su jumis el. paštu per jūsų naudotojo ar naudotojo aptarimo puslapyje esančią nuorodą. Jūsų el. pašto adresas, kitam naudotojui su jumis susisiekus, nėra atskleidžiamas.",
        "prefs-help-email-required": "El. pašto adresas yra būtinas.",
        "prefs-info": "Pagrindinė informacija",
        "prefs-i18n": "Kalbos nustatymai",
        "right-edituserjs": "Redaguoti kitų naudotojų JS failus",
        "right-editmyusercss": "Redaguoti savo vartotojo CSS failus",
        "right-editmyuserjs": "Redaguokite savo naudotojo vartotojo JavaScript failus",
-       "right-viewmywatchlist": "Peržiūrėti savo stebimų sąrašą",
+       "right-viewmywatchlist": "Peržiūrėti savo stebimų sąrašą",
        "right-editmywatchlist": "Keiskite savo stebimųjų sąrašą. Atminkite, kad kai kurie veiksmai vis vien pridės puslapius netgi be tokios teisės.",
        "right-viewmyprivateinfo": "Peržiūrėti asmeninius duomenis (pvz., elektroninis paštas, tikras vardas)",
        "right-editmyprivateinfo": "Keisti asmeninius duomenis (pvz., elektroninis paštas, tikras vardas)",
        "grant-generic": "\"$1\" teisių rinkinys",
        "grant-group-page-interaction": "Sąveikauti su puslapiais",
        "grant-group-file-interaction": "Sąveikauti su medija",
-       "grant-group-watchlist-interaction": "Sąveikauti su savo stebimu sąrašu",
+       "grant-group-watchlist-interaction": "Sąveikauti su savo stebimųjų sąrašu",
        "grant-group-email": "Siųsti el. laišką",
        "grant-group-high-volume": "Atlikti didelės apimties veiklą",
        "grant-group-customization": "Pritaikymas ir parinktys",
        "enhancedrc-history": "istorija",
        "recentchanges": "Naujausi keitimai",
        "recentchanges-legend": "Naujausių keitimų parinktys",
-       "recentchanges-summary": "Å iame puslapyje yra patys naujausi pakeitimai Å¡iame projekte.",
+       "recentchanges-summary": "Žemiau pateikiamas naujausių Å¡io projekto pakeitimų sÄ\85raÅ¡as.",
        "recentchanges-noresult": "Per nurodytą laiką atliktų keitimų, atitinkančių nurodytas sąlygas, nėra.",
        "recentchanges-feed-description": "Sekite pačius naujausius projekto keitimus šiame šaltinyje.",
        "recentchanges-label-newpage": "Šiuo keitimu sukurtas naujas puslapis",
        "listfiles-delete": "trinti",
        "listfiles-summary": "Šiame specialiame puslapyje rodomos visos įkeltos rinkmenos.",
        "listfiles_search_for": "Ieškoti failo pavadinimo:",
-       "listfiles-userdoesnotexist": "Vartotojo paskyrą „$1“ nėra registruota.",
+       "listfiles-userdoesnotexist": "Naudotojo paskyra „$1“ nėra užregistruota.",
        "imgfile": "rinkmena",
        "listfiles": "Failų sąrašas",
        "listfiles_thumb": "Miniatiūra",
        "statistics-users-active-desc": "Naudotojai, kurie per {{PLURAL:$1|paskutinę dieną|paskutines $1 dienų}} padarė keitimų",
        "pageswithprop": "Puslapiai su puslapio atributais",
        "pageswithprop-legend": "Puslapiai su puslapio atributais",
-       "pageswithprop-text": "Šiame puslapyje pateikiami puslapiai, kurie ypač naudoja puslapio atributus.",
-       "pageswithprop-prop": "Ypatybės pavadinimas:",
+       "pageswithprop-text": "Šiame puslapyje pateikiami puslapiai, turintys atitinkamą puslapio atributą.",
+       "pageswithprop-prop": "Atributo pavadinimas:",
        "pageswithprop-submit": "Eiti",
        "pageswithprop-prophidden-long": "ilgo teksto turto vertė paslėpta ($1)",
        "pageswithprop-prophidden-binary": "dvejetainė turto vertė paslėpta ($1)",
        "uncategorizedtemplates": "Šablonai, nepriskirti jokiai kategorijai",
        "unusedcategories": "Nenaudojamos kategorijos",
        "unusedimages": "Nenaudojami failai",
-       "wantedcategories": "Geidžiamiausios kategorijos",
-       "wantedpages": "Geidžiamiausi puslapiai",
+       "wantedcategories": "Reikiamiausios kategorijos",
+       "wantedpages": "Reikiamiausi puslapiai",
        "wantedpages-summary": "Sąrašas neegzistuojančių puslapių su daugiausią nuorodų į juos, išskyrus puslapius, kurie turi tik nukreipimus į juos. Jei norite pamatyti sąrašą neegzistuojančių puslapių, su nukreipimais į juos, žiūrėkite [[{{#special:BrokenRedirects}}|neveikiančių nuorodų sąrašą]].",
        "wantedpages-badtitle": "Neleistinas pavadinimas rezultatų rinkinyje: $1",
-       "wantedfiles": "Trokštami failai",
-       "wantedfiletext-cat": "Sekantys failai yra naudojami, bet neegzistuoja. Čia failai iš išorinių saugyklų gali būti išvardinti, nors jie jose ir egzistuoja. Failai netenkinantys šių sąlygų gali būti <del>perbraukti</del>. Papildomai peržiūrėkite [[:$1|puslapius]], kuriuose yra naudojami čia išvardinti neegzistuojantys failai.",
+       "wantedfiles": "Reikiamiausi failai",
+       "wantedfiletext-cat": "Šiame puslapyje pateikiami failai, kurie yra naudojami, bet neegzistuoja. Čia gali būti išvardinti failai iš išorinių saugyklų, nors jie jose ir egzistuoja. Tokiu atveju failų pavadinimai yra <del>perbraukti</del>. Be to, puslapiai, kuriuose esama neegzistuojančių failų, yra išvardinti [[:$1|čia]].",
        "wantedfiletext-cat-noforeign": "Šie failai yra naudojami, bet neegzistuoja. Be to, puslapiai su šiais failais, kurie neegzistuoja yra išvardinti [[:$1]].",
-       "wantedfiletext-nocat": "Sekantys failai yra naudojami, bet neegzistuoja. Čia failai iš išorinių saugyklų gali būti išvardinti, nors jie jose ir egzistuoja. Failai netenkinantys šių sąlygų gali būti <del>perbraukti</del>.",
+       "wantedfiletext-nocat": "Šiame puslapyje pateikiami failai, kurie yra naudojami, bet neegzistuoja. Čia gali būti išvardinti failai iš išorinių saugyklų, nors jie jose ir egzistuoja. Tokiu atveju failų pavadinimai yra <del>perbraukti</del>.",
        "wantedfiletext-nocat-noforeign": "Šios rinkmenos yra naudojamos, tačiau nesti.",
-       "wantedtemplates": "Trokštami šablonai",
+       "wantedtemplates": "Reikiamiausi šablonai",
        "mostlinked": "Daugiausiai nurodomi puslapiai",
        "mostlinkedcategories": "Daugiausiai nurodomos kategorijos",
        "mostlinkedtemplates": "Daugiausiai nurodomi šablonai",
        "apisandbox-results-fixtoken-fail": "Nepavyko gauti „$1“ žetono.",
        "apisandbox-alert-page": "Laukai šiame puslapyje yra negalimi.",
        "apisandbox-alert-field": "Šio lauko reikšmė yra neteisinga.",
+       "apisandbox-continue": "Tęsti",
+       "apisandbox-continue-clear": "Išvalyti",
        "booksources": "Knygų šaltiniai",
        "booksources-search-legend": "Knygų šaltinių paieška",
        "booksources-search": "Ieškoti",
        "mailnologin": "Nėra adreso",
        "mailnologintext": "Jums reikia būti [[Special:UserLogin|prisijungusiam]] ir turi būti įvestas teisingas el. pašto adresas jūsų [[Special:Preferences|nustatymuose]], kad siųstumėte el. laiškus kitiems nautotojams.",
        "emailuser": "Rašyti laišką šiam naudotojui",
-       "emailuser-title-target": "Siųsti E-pašto žinutę {{GENDER:$1|user}}",
+       "emailuser-title-target": "Siųsti el. pašto žinutę {{GENDER:$1|naudotojui|naudotojai}}",
        "emailuser-title-notarget": "El. pašto vartotojas",
-       "emailpagetext": "Jūs galite pasinaudoti šiuo pavyzdžiu, norėdami nusiųsti elektroninį laišką šiam naudotojui.\nElektroninio pašto adresas, kurį įvedėte [[Special:Preferences|savo naudotojo nustatymuose]], bus rodomas kaip el. pašto siuntėjo adresas, tam, kad gavėjas galėtų jums iškart atsakyti.",
+       "emailpagetext": "Jūs galite pasinaudoti šiuo pavyzdžiu, norėdami nusiųsti elektroninį laišką {{GENDER:$1|šiam naudotojui|šiai naudotojai}}.\nElektroninio pašto adresas, kurį įvedėte [[Special:Preferences|savo naudotojo nustatymuose]], bus rodomas kaip el. pašto siuntėjo adresas tam, kad gavėjas galėtų tiesiogiai jums atsakyti.",
        "defemailsubject": "{{SITENAME}} el. pašto iš vartotojo \" $1 \"",
        "usermaildisabled": "Naudotojo elektroninis paštas išjungtas",
        "usermaildisabledtext": "Jūs negalite siūlsti el. laiško kitiems šio wiki projekto naudotojams.",
        "emailuserfooter": "Šis el. laiškas buvo išsiųstas naudotojo $1 naudotojui $2 naudojant „{{int:emailuser}}“ funkciją {{SITENAME}}.",
        "usermessage-summary": "Paliekamas sistemos pranešimas.",
        "usermessage-editor": "Sistemos pranešėjas",
-       "watchlist": "Stebimų sąrašas",
-       "mywatchlist": "Stebimų sąrašas",
-       "watchlistfor2": "Naudotojo $1 $2",
+       "watchlist": "Stebimų sąrašas",
+       "mywatchlist": "Stebimų sąrašas",
+       "watchlistfor2": "Naudotojas: $1 $2",
        "nowatchlist": "Neturite nei vieno stebimo puslapio.",
        "watchlistanontext": "Prašome prisijungti, kad peržiūrėtumėte ar pakeistumėte elementus savo stebimųjų sąraše.",
        "watchnologin": "Neprisijungęs",
        "addwatch": "Pridėti į stebimųjų sąrašą",
        "addedwatchtext": "\"[[:$1]]\" ir jo aptarimo puslapis buvo įtraukti į Jūsų [[Special:Watchlist|stebėjimo sąrašą]].",
+       "addedwatchtext-talk": "\"[[:$1]]\" ir su juo susijęs puslapis buvo įtraukti į Jūsų [[Special:Watchlist|stebimųjų sąrašą]].",
        "addedwatchtext-short": "Puslapis „$1“ pridėtas į jūsų stebimųjų sąrašą.",
        "removewatch": "Pašalinti iš stebimųjų sąrašo",
        "removedwatchtext": "\"[[:$1]]\" ir jo aptarimo puslapis buvo pašalinti iš Jūsų [[Special:Watchlist|stebėjimo sąrašo]].",
+       "removedwatchtext-talk": "\"[[:$1]]\" ir su juo susijęs puslapis buvo pašalinti iš Jūsų [[Special:Watchlist|stebimųjų sąrašo]].",
        "removedwatchtext-short": "Puslapis „$1“ pašalintas iš jūsų stebimųjų sąrašo.",
        "watch": "Stebėti",
        "watchthispage": "Stebėti šį puslapį",
        "unwatchthispage": "Nustoti stebėti",
        "notanarticle": "Ne turinio puslapis",
        "notvisiblerev": "Versija buvo ištrinta",
-       "watchlist-details": "Stebima {{PLURAL:$1|$1 puslapis|$1 puslapiai|$1 puslapių}} neskaičiuojant aptarimų puslapių.",
+       "watchlist-details": "Stebima {{PLURAL:$1|$1 puslapis|$1 puslapiai|$1 puslapių}}, neskaičiuojant aptarimų puslapių.",
        "wlheader-enotif": "El. pašto pranešimai yra įjungti.",
        "wlheader-showupdated": "Puslapiai pakeisti nuo tada, kai paskutinį kartą apsilankėte juose, yra pažymėti '''pastorintai'''",
        "wlnote": "{{PLURAL:$1|Rodomas '''$1''' paskutinis pakeitimas, atliktas|Rodomi '''$1''' paskutiniai pakeitimai, atlikti|Rodoma '''$1''' paskutinių pakeitimų, atliktų}} per '''$2''' {{PLURAL:$2|paskutinę valandą|paskutines valandas|paskutinių valandų}}, nuo $3 $4.",
        "enotif_lastvisited": "Užeikite į $1, jei norite matyti pakeitimus nuo paskutiniojo apsilankymo.",
        "enotif_lastdiff": "Užeikite į $1, jei norite pamatyti šį pakeitimą.",
        "enotif_anon_editor": "anoniminis naudotojas $1",
-       "enotif_body": "$WATCHINGUSERNAME,\n\n\n$PAGEEDITDATE {{SITENAME}} projekte $PAGEEDITOR $CHANGEDORCREATED puslapį „$PAGETITLE“, dabartinę versiją rasite adresu $PAGETITLE_URL.\n\n$NEWPAGE\n\nRedaguotojo komentaras: $PAGESUMMARY $PAGEMINOREDIT\n\nSusisiekti su redaguotoju:\nel. paštu: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nDaugiau pranešimų apie vėlesnius pakeitimus nebus siunčiama, jei neapsilankysite puslapyje.\nJūs taip pat galite išjungti pranešimo žymę visiems jūsų stebimiems puslapiams savo stebimųjų sąraše.\n\n Jūsų draugiškoji projekto {{SITENAME}} pranešimų sistema\n\n--\nNorėdami pakeisti e-paštu siunčiamų pranešimų nustatymus, užeikite į\n{{canonicalurl:{{#special:Preferences}}}}\n\nNorėdami pakeisti stebimų puslapių nustatymus, užeikite į\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nNorėdami puslapį iš stebimų puslapių sąrašo, užeikite į\n$UNWATCHURL\n\nAtsiliepimai ir pagalba:\n$HELPPAGE",
+       "enotif_body": "$WATCHINGUSERNAME,\n\n\n$PAGEEDITDATE {{SITENAME}} projekte $PAGEEDITOR $CHANGEDORCREATED puslapį „$PAGETITLE“, dabartinę versiją rasite adresu $PAGETITLE_URL.\n\n$NEWPAGE\n\nRedaguotojo komentaras: $PAGESUMMARY $PAGEMINOREDIT\n\nSusisiekti su redaguotoju:\nel. paštu: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nDaugiau pranešimų apie vėlesnius pakeitimus nebus siunčiama, jei neapsilankysite puslapyje.\nJūs taip pat galite išjungti pranešimo žymę visiems jūsų stebimiems puslapiams savo stebimųjų sąraše.\n\n Jūsų draugiškoji projekto {{SITENAME}} pranešimų sistema\n\n--\nNorėdami pakeisti e-paštu siunčiamų pranešimų nustatymus, užeikite į\n{{canonicalurl:{{#special:Preferences}}}}\n\nNorėdami pakeisti stebimųjų puslapių nustatymus, užeikite į\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nNorėdami puslapį iš stebimųjų puslapių sąrašo, užeikite į\n$UNWATCHURL\n\nAtsiliepimai ir pagalba:\n$HELPPAGE",
        "created": "sukurė",
        "changed": "pakeitė",
        "deletepage": "Trinti puslapį",
        "delete-toobig": "Šis puslapis turi ilgą keitimų istoriją, daugiau nei $1 {{PLURAL:$1|revizija|revizijos|revizijų}}. Tokių puslapių trynimas yra apribotas, kad būtų išvengta atsitiktinio {{SITENAME}} žlugdymo.",
        "delete-warning-toobig": "Šis puslapis turi ilgą keitimų istoriją, daugiau nei $1 {{PLURAL:$1|revizija|revizijos|revizijų}}. Trinant jis gali sutrikdyti {{SITENAME}} duomenų bazės operacijas; būkite atsargūs.",
        "deleteprotected": "Jūs šio puslapio ištrinti negalite, nes jis apsaugotas.",
-       "deleting-backlinks-warning": "'''Dėmesio:''' [[Special:WhatLinksHere/{{FULLPAGENAME}}|Kiti puslapiai]] nurodo ar įtraukia puslapį, kurį ruošiatės trinti.",
+       "deleting-backlinks-warning": "<strong>Dėmesio:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Kiti puslapiai]] nurodo ar įtraukia puslapį, kurį ruošiatės trinti.",
        "rollback": "Atmesti keitimus",
        "rollbacklink": "atmesti",
        "rollbacklinkcount": "atmesti $1 {{PLURAL:$1|keitimą|keitimus}}",
        "rollbacklinkcount-morethan": "atmesti daugiau nei $1 {{PLURAL:$1|keitimą|keitimų}}",
        "rollbackfailed": "Atmetimas nepavyko",
+       "rollback-missingrevision": "Nepavyko įkelti versijos duomenų.",
        "cantrollback": "Negalima atmesti redagavimo; paskutinis keitęs naudotojas yra šio puslapio autorius.",
        "alreadyrolled": "Nepavyko atmesti paskutinio [[User:$2|$2]] ([[User talk:$2|Aptarimas]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) daryto puslapio [[:$1]] keitimo;\nkažkas jau pakeitė puslapį arba suspėjo pirmas atmesti keitimą.\n\nPaskutimas keitimas darytas naudotojo [[User:$3|$3]] ([[User talk:$3|Aptarimas]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Pateiktas toks keitimo paaiškinimas: <em>$1</em>.",
        "revertpage": "Atmestas [[Special:Contributions/$2|$2]] ([[User talk:$2|Aptarimas]]) pakeitimas; sugrąžinta [[User:$1|$1]] versija",
        "revertpage-nouser": "Atversti pakeitimai paslėpto vartotojo, grąžino prieš tai buvusią versiją {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Atmesti $1 pakeitimai;\ngrąžinta prieš tai buvusi $2 versija.",
+       "rollback-success-notify": "Atmesti $1 pakeitimai;\ngrąžinta prieš tai buvusi $2 versija. [$3 Rodyti skirtumus]",
        "sessionfailure-title": "Sesijos klaida",
        "sessionfailure": "Atrodo yra problemų su jūsų prisijungimo sesija; šis veiksmas buvo atšauktas kaip atsargumo priemonė prieš sesijos vogimą.\nPrašome paspausti „atgal“ ir perkraukite puslapį iš kurio atėjote, ir pamėginkite vėl.",
        "changecontentmodel": "Keisti puslapio turinio modelį",
        "changecontentmodel-cannot-convert": "Turinys [[:$1]] negali būti konvertuotas į $2 tipą.",
        "changecontentmodel-nodirectediting": "$1 turinio modelis nepalaiko tiesioginio redagavimo",
        "changecontentmodel-emptymodels-title": "Nėra prieinamų turinio modelių",
+       "changecontentmodel-emptymodels-text": "[[:$1]] turinys negali būti konvertuotas į jokį tipą.",
        "log-name-contentmodel": "Turinio modelio kaitos istorija",
        "log-description-contentmodel": "Įvykiai susiję su puslapio turinio modeliu",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|sukūrė}} puslapį $3, naudodamas nestandartinį turinio modelį \"$5\"",
        "logentry-contentmodel-change": "$1 {{GENDER:$2|atnaujino}} puslapio $3 turinio modelį iš $4 į $5",
        "logentry-contentmodel-change-revertlink": "atšaukti",
        "logentry-contentmodel-change-revert": "atšaukti",
        "protectlogtext": "Žemiau yra puslapių užrakinimų bei atrakinimų sąrašas.\nDabar veikiančių puslapių apsaugų sąrašą rasite [[Special:ProtectedPages|apsaugotų puslapių sąraše]].",
        "protectedarticle": "užrakino „[[$1]]“",
        "modifiedarticleprotection": "pakeistas „[[$1]]“ apsaugos lygis",
-       "unprotectedarticle": "pašalino apsaugą nuo „[[$1]]“",
+       "unprotectedarticle": "atrakino „[[$1]]“",
        "movedarticleprotection": "perkelti apsaugos nustatymai iš „[[$2]]“ į „[[$1]]“",
        "protect-title": "Nustatomas apsaugos lygis puslapiui „$1“",
        "protect-title-notallowed": "Peržiūrėti \"$1\" apsaugos lygį",
        "undeletehistorynoadmin": "Šis puslapis buvo ištrintas. Žemiau rodoma trynimo priežastis bei kas redagavo puslapį iki ištrynimo. Ištrintų puslapių tekstas yra galimas tik administratoriams.",
        "undelete-revision": "Ištrinta $1 versija, kurią $4 d. $5 sukūrė $3:",
        "undeleterevision-missing": "Neteisinga arba dingusi versija. Jūs turbūt turite blogą nuorodą, arba versija buvo atkurta arba pašalinta iš archyvo.",
+       "undeleterevision-duplicate-revid": "{{PLURAL:$1|Viena versija|$1 versijos}} negalėjo būti atkurtos, nes {{PLURAL:$1|jos|jų}} <code>rev_id</code> jau buvo naudojamas.",
        "undelete-nodiff": "Nerasta jokių ankstesnių versijų.",
        "undeletebtn": "Atkurti",
        "undeletelink": "žiūrėti/atkurti",
        "sp-contributions-newbies": "Rodyti tik naujų paskyrų keitimus",
        "sp-contributions-newbies-sub": "Neseniai prisiregistravusieji",
        "sp-contributions-newbies-title": "Naujai užsiregistravusių naudotojų indėlis",
-       "sp-contributions-blocklog": "Blokavimų sąrašas",
-       "sp-contributions-suppresslog": "ištrintas naudotojo indėlis",
-       "sp-contributions-deleted": "ištrintas naudotojo indėlis",
+       "sp-contributions-blocklog": "blokavimų sąrašas",
+       "sp-contributions-suppresslog": "ištrintas {{GENDER:$1|naudotojo|naudotojos}} indėlis",
+       "sp-contributions-deleted": "ištrintas {{GENDER:$1|naudotojo|naudotojos}} indėlis",
        "sp-contributions-uploads": "įkėlimai",
-       "sp-contributions-logs": "Specialiųjų veiksmų sąrašas",
+       "sp-contributions-logs": "specialiųjų veiksmų sąrašas",
        "sp-contributions-talk": "Aptarimas",
        "sp-contributions-userrights": "naudotojų teisių valdymas",
        "sp-contributions-blocked-notice": "Šis naudotojas šiuo metu užblokuotas.\nPateikiamas paskutinis blokavimo istorijos įrašas.",
        "sp-contributions-blocked-notice-anon": "Šis IP adresas yra užblokuotas.\nPaskutinis blokavimo įrašas pateikiamas žemiau:",
-       "sp-contributions-search": "Ieškoti įnašo",
+       "sp-contributions-search": "Ieškoti indėlio",
        "sp-contributions-username": "IP adresas arba naudotojo vardas:",
        "sp-contributions-toponly": "Rodyti tik paskutinius keitimus",
        "sp-contributions-newonly": "Rodyti tik tuos keitimus, kuriais sukurti nauji straipsniai",
-       "sp-contributions-hideminor": "Slėpti nedidelius pakeitimus",
+       "sp-contributions-hideminor": "Slėpti smulkius pakeitimus",
        "sp-contributions-submit": "Ieškoti",
        "whatlinkshere": "Susiję puslapiai",
        "whatlinkshere-title": "Puslapiai, kurie nurodo į „$1“",
        "movenosubpage": "Šis puslapis neturi subpuslapių.",
        "movereason": "Priežastis:",
        "revertmove": "atmesti",
-       "delete_and_move_text": "==Reikia ištrinti==\n\nPaskirties puslapis „[[:$1]]“ jau yra. Ar norite jį ištrinti, kad galėtumėte pervardinti?",
+       "delete_and_move_text": "Paskirties puslapis „[[:$1]]“ jau yra. Ar norite jį ištrinti, kad galėtumėte pervardinti?",
        "delete_and_move_confirm": "Taip, trinti puslapį",
        "delete_and_move_reason": "Ištrinta dėl perkėlimo iš \"[[$1]]\"",
        "selfmove": "Šaltinio ir paskirties pavadinimai yra tokie patys; negalima pervardinti puslapio į save.",
        "move-leave-redirect": "Pervadinant palikti nukreipimą",
        "protectedpagemovewarning": "'''Dėmesio:''' Šis puslapis buvo užrakintas, kad tik naudotojai su administratoriaus teisėmis galėtų jį pervadinti.\nNaujausias įrašas žurnale yra pateiktas žemiau:",
        "semiprotectedpagemovewarning": "'''Pastaba''': Šis puslapis buvo užrakintas, kad tik registruoti naudotojai galėtų jį redaguoti.\nNaujausias įrašas žurnale yra pateiktas žemiau:",
-       "move-over-sharedrepo": "== Rinkmena jau yra ==\n[[:$1]] esti bendrojoje saugykloje. Įkėlus rinkmeną šiuo pavadinimu, ji pakeis bendrąją rinkmeną.",
+       "move-over-sharedrepo": "[[:$1]] esti bendrojoje saugykloje. Įkėlus rinkmeną šiuo pavadinimu, ji pakeis bendrąją rinkmeną.",
        "file-exists-sharedrepo": "Pasirinktas failo pavadinimas jau yra naudojamas bendrojoje saugykloje.\nPrašome pasirinkti kitą pavadinimą.",
        "export": "Eksportuoti puslapius",
        "exporttext": "Galite eksportuoti vieno puslapio tekstą ir istoriją ar kelių puslapių vienu metu tame pačiame XML atsakyme.\nŠie puslapiai galės būti importuojami į kitą projektą, veikiantį MediaWiki pagrindu, per [[Special:Import|importo puslapį]].\n\nNorėdami eksportuoti puslapius, įveskite pavadinimus žemiau esančiame tekstiniame lauke po vieną pavadinimą eilutėje, taip pat pasirinkite ar norite eksportuoti ir istoriją ar tik dabartinę versiją su paskutinio redagavimo informacija.\n\nPastaruoju atveju, jūs taip pat galite naudoti nuorodą, pvz. [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] puslapiui „[[{{MediaWiki:Mainpage}}]]“.",
        "import-nonewrevisions": "Nebuvo importuotos jokios versijos (visos jau buvo įkeltos arba praleistos dėl klaidų).",
        "xml-error-string": "$1 $2 eilutėje, $3 stulpelyje ($4 baitas): $5",
        "import-upload": "Įkelti XML duomenis",
-       "import-token-mismatch": "Sesijos duomenys prarasti. Bandykite iš naujo.",
+       "import-token-mismatch": "Sesijos duomenys prarasti.\n\nGali būti, kad esate atsijungęs. <strong>Prašome patikrinti, ar vis dar esate prisijungęs, ir pabandyti iš naujo</strong>.\nJei ir toliau nepavyksta, pamėginkite [[Special:UserLogout|atsijungti]] ir vėl prisijungti, taip pat patikrinkite, ar jūsų naršyklė priima šios svetainės slapukus.",
        "import-invalid-interwiki": "Nepavyko importuoti iš nurodyto wiki projekto.",
        "import-error-edit": "Puslapis \"$1\" nebuvo įkeltas, nes jūs neturite teisės jį redaguoti.",
        "import-error-create": "Puslapis „$1“ nebuvo importuotas, nes jūs neturite teisės jį sukurti.",
        "confirm-unwatch-button": "Gerai",
        "confirm-unwatch-top": "Pašalinti šį puslapį iš jūsų stebimųjų sąrašo?",
        "confirm-rollback-button": "Gerai",
+       "confirm-rollback-top": "Atmesti šio puslapio pakeitimus?",
        "quotation-marks": "„$1“",
        "imgmultipageprev": "← ankstesnis puslapis",
        "imgmultipagenext": "kitas puslapis →",
        "lag-warn-high": "Dėl didelio duomenų bazės atsilikimo pakeitimai, naujesni nei $1 {{PLURAL:$1|sekundė|sekundės|sekundžių}}, šiame sąraše gali būti nerodomi.",
        "watchlistedit-normal-title": "Redaguoti stebimųjų sąrašą",
        "watchlistedit-normal-legend": "Šalinti puslapius iš stebimųjų sąrašo",
-       "watchlistedit-normal-explain": "Žemiau yra rodomi puslapiai jūsų stebimųjų sąraše.\nNorėdami pašalinti puslapį, prie jo uždėkite varnelė ir paspauskite „{{int:Watchlistedit-normal-submit}}“.\nJūs taip pat galite [[Special:EditWatchlist/raw|redaguoti grynąjį stebimųjų sąrašą]].",
+       "watchlistedit-normal-explain": "Žemiau yra rodomi puslapiai jūsų stebimųjų sąraše.\nNorėdami pašalinti puslapį, pažymėkite greta esančią varnelę ir paspauskite „{{int:Watchlistedit-normal-submit}}“.\nJūs taip pat galite [[Special:EditWatchlist/raw|redaguoti grynąjį stebimųjų sąrašą]].",
        "watchlistedit-normal-submit": "Šalinti puslapius",
        "watchlistedit-normal-done": "$1 {{PLURAL:$1|puslapis buvo pašalintas|puslapiai buvo pašalinti|puslapių buvo pašalinta}} iš jūsų stebimųjų sąrašo:",
        "watchlistedit-raw-title": "Redaguoti grynąjį stebimųjų sąrašą",
        "redirect-file": "Failo vardas",
        "redirect-logid": "Žurnalo įrašo ID",
        "redirect-not-exists": "Vertė nėra nustatyta",
-       "fileduplicatesearch": "Ieškoti dublikuotų failų",
+       "fileduplicatesearch": "Ieškoti pasikartojančių failų",
        "fileduplicatesearch-summary": "Pasikartojančių failų paieška pagal jų kontrolinę sumą.",
        "fileduplicatesearch-filename": "Failo vardas:",
        "fileduplicatesearch-submit": "Ieškoti",
        "logentry-move-move-noredirect": "$1 {{GENDER:$2|perkėlė}} puslapį $3 į $4 be nukreipimo",
        "logentry-move-move_redir": "$1 {{GENDER:$2|perkėlė}} puslapį $3 į $4 (anksčiau buvo nukreipiamasis)",
        "logentry-move-move_redir-noredirect": "$1 {{GENDER:$2|pervadino}} puslapį $3 į $4, nesukurdamas nukreipimo",
-       "logentry-patrol-patrol": "$1 {{GENDER:$2|payžėmjo}} versiją $4 puslapio $3 kaip patruliuojama",
-       "logentry-patrol-patrol-auto": "$1 automatiškai {{GENDER:$2|pažymėjo}} versiją $4 puslapio $3 kaip patruliuojama",
-       "logentry-newusers-newusers": "Vartotojo paskyra $1 buvo {{GENDER:$2|sukurta}}",
+       "logentry-patrol-patrol": "$1 {{GENDER:$2|pažymėjo}} kaip patikrintą puslapio $3 versiją $4",
+       "logentry-patrol-patrol-auto": "$1 automatiškai {{GENDER:$2|pažymėjo}} kaip patikrintą puslapio $3 versiją $4",
+       "logentry-newusers-newusers": "Naudotojo paskyrą $1 {{GENDER:$2|sukūrė}}",
        "logentry-newusers-create": "$1 sukūrė naudotojo paskyrą",
-       "logentry-newusers-create2": "Vartotojo paskyra $3 buvo {{GENDER:$2|sukurta}} $1",
-       "logentry-newusers-byemail": "Vartotojo paskyra $3 buvo {{GENDER:$2|sukurta}} $1 ir slaptažodis išsiųstas el. paštu",
-       "logentry-newusers-autocreate": "Vartotojo paskyra $1 buvo {{GENDER:$2|sukurta}} automatiškai",
+       "logentry-newusers-create2": "$1 sukūrė naudotojo paskyrą $3",
+       "logentry-newusers-byemail": "Naudotojo paskyrą $3 {{GENDER:$2|sukūrė}} $1, slaptažodis išsiųstas el. paštu",
+       "logentry-newusers-autocreate": "Naudotojo paskyra $1 buvo {{GENDER:$2|sukurta}} automatiškai",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|perkėlė}} apsaugos nustatymus iš $4 į $3",
-       "logentry-protect-unprotect": "$1 {{GENDER:$2|pašalino}} apsaugą nuo $3",
-       "logentry-protect-protect": "$1 {{GENDER:$2|apsaugojo}} $3 $4",
-       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|apsaugojo}} $3 $4 [pakopinė]",
+       "logentry-protect-unprotect": "$1 {{GENDER:$2|atrakino}} $3",
+       "logentry-protect-protect": "$1 {{GENDER:$2|užrakino}} $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|užrakino}} $3 $4 [pakopinė]",
        "logentry-protect-modify": "$1 {{GENDER:$2|pakeitė}} apsaugos lygį $3 $4",
        "logentry-protect-modify-cascade": "$1 {{GENDER:$2|pakeitė}} apsaugos lygį $3 $4 [pakopinė]",
        "logentry-rights-rights": "$1 {{GENDER:$2|pakeitė}} grupės narystę $3 iš $4 į $5",
        "feedback-useragent": "Vartotojo veiksnys:",
        "searchsuggest-search": "Ieškoti",
        "searchsuggest-containing": "turintys",
+       "api-error-autoblocked": "Jūsų IP adresas buvo automatiškai užblokuotas, nes jį naudojo užblokuotas naudotojas.",
        "api-error-badaccess-groups": "Jums neleidžiama įkelti failus į šią wiki.",
        "api-error-badtoken": "Vidinė klaida: blogai atpažinimo ženklas.",
+       "api-error-blocked": "Jus buvote užblokuotas, kad negalėtumėte redaguoti.",
        "api-error-copyuploaddisabled": "Siuntimas pagal URL yra išjungtas šiame serveryje.",
        "api-error-duplicate": "Jau {{PLURAL:$1|yra kitas failas|yra kiti failai}} puslapyje su tuo pačiu turiniu.",
        "api-error-duplicate-archive": "Jau {{PLURAL:$1|buvo kitas failas|buvo kitų failų}} puslapyje su tuo pačiu turiniu, bet {{PLURAL:$1|buvo ištrintas|buvo ištrinti}}.",
        "api-error-nomodule": "Vidinė klaida: nėra nustatytas įkėlimų modulis.",
        "api-error-ok-but-empty": "Vidinė klaida: nėra atsakymo iš serverio.",
        "api-error-overwrite": "Perrašymas esamą failą neleidžiamas.",
+       "api-error-ratelimited": "Jūs per trumpą laiko tarpą bandote įkelti daugiau failų, nei leidžiama šiame projekte.\nPabandykite dar kartą po keleto minučių.",
        "api-error-stashfailed": "Vidinė klaida: serveriui nepavyko išsaugoti laikinąjį failą.",
        "api-error-publishfailed": "Vidinė klaida: serveriui nepavyko paskelbti laikino failo.",
        "api-error-stasherror": "Įvyko klaida keliant failą į laikyklą.",
        "api-error-unknownerror": "Nežinoma klaida: \"$1\"",
        "api-error-uploaddisabled": "Įkėlimas išjungtas šioje wiki.",
        "api-error-verification-error": "Šis failas gali būti sugadintas arba turi neteisingą papildinį.",
+       "api-error-was-deleted": "Failas tokiu pavadinimu anksčiau jau yra buvęs įkeltas, o paskui ištrintas.",
        "duration-seconds": "$1 {{PLURAL:$1|sekundė|sekundės|sekundžių}}",
        "duration-minutes": "$1 {{PLURAL:$1|minutė|minutės|minučių}}",
        "duration-hours": "$1 {{PLURAL:$1|valanda|valandos|valandų}}",
        "expand_templates_generate_xml": "Rodyti XML nagrinėjimo medį",
        "expand_templates_generate_rawhtml": "Rodyti gryną HTML",
        "expand_templates_preview": "Peržiūra",
-       "expand_templates_preview_fail_html": "<em>Nes {{SITENAME}} turi įgalinta gryną HTML ir įvyko sesijos duomenų praradimas, peržiūra yra paslėpta kaip atsargos priemonė prieš JavaScript atakas.</em>\n\n<strong>Jei tai teisėtas peržiūros bandymas, prašome bandyti dar kartą.</strong>\nJei tai vistiek neveikia, pabandykite [[Special:UserLogout|atsijungti]] ir vėl prisijungti.",
+       "expand_templates_preview_fail_html": "<em>Kadangi {{SITENAME}} turi įgalinta gryną HTML ir įvyko sesijos duomenų praradimas, peržiūra yra paslėpta kaip atsargos priemonė prieš JavaScript atakas.</em>\n\n<strong>Jei tai teisėtas peržiūros bandymas, prašome bandyti dar kartą.</strong>\nJei ir toliau neveikia, pabandykite [[Special:UserLogout|atsijungti]] ir vėl prisijungti, taip pat patikrinkite, ar jūsų naršyklė priima šios svetainės slapukus.",
        "expand_templates_preview_fail_html_anon": "<em>Nes {{SITENAME}} turi įgalinta gryną HTML ir jūs esate neprisijungęs, peržiūra paslėpta kaip atsargumo priemonė prieš JavaScript atakas.</em>\n\n<strong>Jei tai teisėtas peržiūros bandymas prašome [[Special:UserLogin|prisijungti]] ir bandyti vėl.</strong>",
        "expand_templates_input_missing": "Turite pateikti bent truputį įvesties teksto.",
        "pagelanguage": "Keisti puslapio kalbą",
        "log-action-filter-delete": "Trynimo tipas:",
        "log-action-filter-import": "Importo tipas:",
        "log-action-filter-managetags": "Žymės tvarkymo veiksmo tipas:",
-       "log-action-filter-move": "Kėlimo tipas:",
+       "log-action-filter-move": "Perkėlimo tipas:",
        "log-action-filter-newusers": "Paskyros kūrimo tipas:",
+       "log-action-filter-patrol": "Patikrinimo tipas:",
        "log-action-filter-protect": "Apsaugos tipas:",
        "log-action-filter-rights": "Teisių tipo keitimas:",
        "log-action-filter-upload": "Įkėlimo tipas:",
        "log-action-filter-managetags-delete": "Žymės trynimas",
        "log-action-filter-managetags-activate": "Žymės aktyvavimas",
        "log-action-filter-managetags-deactivate": "Žymės deaktyvavimas",
+       "log-action-filter-move-move": "Perkėlimai, nepakeičiant nukreipimų",
+       "log-action-filter-move-move_redir": "Perkėlimai, pakeičiant buvusius nukreipimus",
        "log-action-filter-newusers-autocreate": "Automatinis kūrimas",
+       "log-action-filter-patrol-patrol": "„Rankinis“ patikrinimas",
+       "log-action-filter-patrol-autopatrol": "Automatinis patikrinimas",
        "log-action-filter-protect-protect": "Apsauga",
        "log-action-filter-protect-modify": "Apsaugos keitimas",
        "log-action-filter-protect-move_prot": "Apsauga perkelta",
        "log-action-filter-rights-autopromote": "Automatinis keitimas",
        "log-action-filter-upload-upload": "Naujas įkėlimas",
        "log-action-filter-upload-overwrite": "Kelti iš naujo",
+       "authmanager-authn-not-in-progress": "Autentifikavimas nevyksta arba buvo prarasti sesijos duomenys. Prašome pradėti iš naujo.",
        "authmanager-create-disabled": "Paskyros kūrimas yra išjungtas.",
        "authmanager-create-from-login": "Norėdami sukurti paskyrą užpildykite laukelius žemiau.",
+       "authmanager-create-not-in-progress": "Paskyros kūrimas nevyksta arba buvo prarasti sesijos duomenys. Prašome pradėti iš naujo.",
+       "authmanager-link-not-in-progress": "Paskyrų susiejimas nevyksta arba buvo prarasti sesijos duomenys. Prašome pradėti iš naujo.",
        "authmanager-authplugin-setpass-failed-title": "Slaptažodžio keitimas nepavyko",
        "authmanager-authplugin-setpass-bad-domain": "Negalimas domenas.",
        "authmanager-autocreate-noperm": "Automatinis paskyros kūrimas neleidžiamas.",
        "authmanager-provider-password": "Autentifikacija slaptažodžiu",
        "authmanager-provider-password-domain": "Autentifikavimas slaptažodžiu ir domenu",
        "authmanager-provider-temporarypassword": "Laikinas slaptažodis",
+       "authprovider-confirmlink-message": "Remiantis naujausiais jūsų prisijungimo bandymais, šios paskyros gali būti susietos su jūsų wiki paskyra. Jas susieję, galėsite prisijungti per šias paskyras. Prašome pasirinkti, kurios iš jų turėtų būti susietos.",
        "authprovider-confirmlink-request-label": "Paskyros, kurios turėtų būti susietos",
        "authprovider-confirmlink-success-line": "$1: Susieta sėkmingai.",
        "authprovider-confirmlink-failed": "Paskyros susiejimas nebuvo visiškai sėkmingas: $1",
        "authprovider-resetpass-skip-label": "Praleisti",
        "authprovider-resetpass-skip-help": "Praleisti slaptažodžio perstatymą.",
        "specialpage-securitylevel-not-allowed-title": "Neleidžiama",
+       "specialpage-securitylevel-not-allowed": "Apgailestaujame, tačiau jūs negalite naudotis šiuo puslapiu, nes nepavyko patvirtinti jūsų tapatybės.",
        "cannotauth-not-allowed-title": "Teisė nesuteikta",
        "cannotauth-not-allowed": "Jūs negalite naudotis šiuo puslapiu",
        "credentialsform-account": "Paskyros vardas:",
index dd81bea..1095c38 100644 (file)
        "talk": "Diskusija",
        "views": "Apskates",
        "toolbox": "Rīki",
+       "tool-link-emailuser": "Nosūtīt e-pastu {{GENDER:$1|šim dalībniekam|šai dalībniecei}}",
        "userpage": "Skatīt dalībnieka lapu",
        "projectpage": "Skatīt projekta lapu",
        "imagepage": "Skatīt faila lapu",
index eca8513..5c690ef 100644 (file)
        "sp-contributions-newbies-title": "Придонеси на нови корисници",
        "sp-contributions-blocklog": "Дневник на блокирања",
        "sp-contributions-suppresslog": "притаени придонесите на {{GENDER:$1|корисникот|корисничката}}",
-       "sp-contributions-deleted": "избришани придонесите на {{GENDER:$1|корисникот|корисничката}}",
+       "sp-contributions-deleted": "избришани придонеси на {{GENDER:$1|корисникот}}",
        "sp-contributions-uploads": "подигања",
        "sp-contributions-logs": "дневници",
        "sp-contributions-talk": "разговор",
        "movelogpagetext": "Подолу е наведен список на преместени страници.",
        "movesubpage": "{{PLURAL:$1|Потстраница|Потстраници}}",
        "movesubpagetext": "Оваа страница има $1 {{PLURAL:$1|потстраница прикажана|потстраници прикажани}} подолу.",
+       "movesubpagetalktext": "Оваа страница има $1 {{PLURAL:$1|потстраница прикажана|потстраници прикажани}} подолу.",
        "movenosubpage": "Оваа страница нема потстраници.",
        "movereason": "Причина:",
        "revertmove": "врати",
        "newimages-showbots": "Прикажувај подигања од ботови",
        "newimages-hidepatrolled": "Сокриј испатролриани подигања",
        "noimages": "Нема ништо.",
+       "gallery-slideshow-toggle": "Преод на минијатури",
        "ilsubmit": "Барај",
        "bydate": "по датум",
        "sp-newimages-showfrom": "Прикажи нови податотеки од $2, $1",
        "feedback-thanks": "Благодариме! Вашиот одѕив е објавен на страницата „[$2 $1]“.",
        "feedback-thanks-title": "Ви благодариме!",
        "feedback-useragent": "Кориснички вршител:",
-       "searchsuggest-search": "Пребарување",
+       "searchsuggest-search": "Пребарајте по {{SITENAME}}",
        "searchsuggest-containing": "содржи...",
        "api-error-autoblocked": "Вашата IP-адреса е автоматски блокирана бидејќи ја има користено блокиран корисник.",
        "api-error-badaccess-groups": "Не ви е дозволено да подигате податотеки на ова вики.",
        "usercssispublic": "Напомена: потстраниците со CSS не треба да содржат дсоверливи податоци бидејќи истите се видливи и за други корисници.",
        "restrictionsfield-badip": "Неважечки IP-дијапазон на адреси: $1",
        "restrictionsfield-label": "Допуштени IP-опсези:",
-       "restrictionsfield-help": "Една IP-адреса или CIDR-опсег по ред. За да овозможите сè, користете<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "Една IP-адреса или CIDR-опсег по ред. За да овозможите сè, користете<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Грешка: $1",
+       "edit-error-long": "Грешки:\n\n$1"
 }
index 0d18c0d..3e85f15 100644 (file)
        "category-file-count-limited": "खालील {{PLURAL:$1|संचिका|$1 संचिका}} या वर्गात आहेत.",
        "listingcontinuesabbrev": "पुढे चला",
        "index-category": "अनुक्रमित पाने",
-       "noindex-category": "विना-à¤\85नà¥\81à¤\95à¥\8dरमित पाने",
+       "noindex-category": "à¤\85नà¥\81à¤\95à¥\8dरमित à¤¨à¤¸à¤²à¥\87लà¥\80 पाने",
        "broken-file-category": "तुटलेल्या संचिका दुव्यांसह असलेली पाने",
        "about": "च्या विषयी",
        "article": "आशयाचे पान",
        "movelogpagetext": "स्थानांतरित केलेल्या पानांची यादी.",
        "movesubpage": "{{PLURAL:$1|उपपान|उपपाने}}",
        "movesubpagetext": "या पानास $1 {{PLURAL:$1|उपपान|उपपाने}} असून ती पुढे दर्शवली आहेत:",
+       "movesubpagetalktext": "संबंधित चर्चा पानाची $1 {{PLURAL:$1|उपपान|उपपाने}} खाली दर्शविली आहेत.",
        "movenosubpage": "या पानात उपपाने नाहीत.",
        "movereason": "कारण:",
        "revertmove": "पूर्वपदास न्या",
        "feedback-thanks": " \"[$2 $1]\" या पानात आपला पश्चप्रदाय (फिडबॅक) टाकत आहोत.",
        "feedback-thanks-title": "आपणास धन्यवाद!",
        "feedback-useragent": "सदस्य प्रतिनीधी:",
-       "searchsuggest-search": "शोधा",
+       "searchsuggest-search": "शोधा {{SITENAME}}",
        "searchsuggest-containing": ".......हे असलेले",
        "api-error-badaccess-groups": "आपणास ह्या विकिवर संचिका चढवण्याची परवानगी नाही",
        "api-error-badtoken": "अंतर्गत चूक: अयोग्य टोकन",
        "randomrootpage": "अविशिष्ट मूळ पान",
        "log-action-filter-suppress-block": "रोधामार्फत सदस्य दाबणे",
        "changecredentials": "अधिकारपत्रे (क्रेडेंटियल्स)बदला",
-       "removecredentials": "अधिकारपत्रे (क्रेडेंटियल्स) हटवा"
+       "removecredentials": "अधिकारपत्रे (क्रेडेंटियल्स) हटवा",
+       "edit-error-short": "त्रुटी: $1",
+       "edit-error-long": "त्रुटी:$1"
 }
index 6e71765..ddf7c41 100644 (file)
        "category-empty": "''Cah ahtlein inīn neneuhcāyōc.''",
        "hidden-categories": "{{PLURAL:$1|tlatlàtìlli tlaìxmatkàyòtlàlilòtl|tlatlàtìltìn tlaìxmatkàyòtlàlilòme}}",
        "hidden-category-category": "Tlatlàtìlkàtlaìxmatkàtlàlilòmë",
-       "category-subcat-count": "{{PLURAL:$2|Inìn tlaìxmatkàyòtlàlilòtl kipia san inìn tlaìxmatkàyòtlàlilòpilli.|Inìn tlaìxmatkàyòtlàlilòtl {{PLURAL:$1|kipia inìn tlaìxmatkàyòtlàlilòpilli|kimpia inîke $1 tlaìxmatkàyòtlàlilòpiltìn}}, ìpan $2.}}",
+       "category-subcat-count": "{{PLURAL:$2|Inin neneuhcayotl zan quipiya in tetoquilli tlani-neneuhcayotl.|Inn neneuhcayotl {{PLURAL:$1|quipiya intetoquilli tlani-neneuhcayotl|in tetoquiltin $1 tlani-neneuhcayomeh}}, itech tlacecempohualoni $2.}}",
        "category-subcat-count-limited": "Inīn {{PLURAL:$1|neneuhcāyōtzintli cah|$1 neneuhcāyōtzintli cateh}} inīn neneuhcāyōc.",
-       "category-article-count": "{{PLURAL:$2|Inìn tlaìxmatkàyòtlàlilòtl san kipia|Inìn tlaìxmatkàyòtlàlilòtl kimpia {{PLURAL:$1|inìn tlaìxtlapalli|inîke $1 tlaìxtlapaltìn}}, ìwikpa $2.}}",
+       "category-article-count": "{{PLURAL:$2|Inin neneuhcayotl zan quipiya in tetoquilli tlahcuilolli.|{{PLURAL:$1|In tetoquilli tlahcuilolli itech pohui|In tetoquiltin $1 tlahcuiloltin itech pohui}}, inin neneuhcayotl itech tlacecempohualoni ipan $2.}}",
        "category-article-count-limited": "Inīn {{PLURAL:$1|zāzanilli cah|$1 zāzanilli cateh}} inīn neneuhcāyōc.",
        "category-file-count": "{{PLURAL:$2|Inìn tlaìxmatkàyòtlàlilòtl san kipia|Inìn tlaìxmatkàyòtlalilòtl kimpia {{PLURAL:$1|inìn èwalli|inîke $1 èwaltìn}}, ìwikpa $2.}}",
        "category-file-count-limited": "{{PLURAL:$1|Inìn tlâkuilòlèwalli kä|Inîkë $1 tlâkuilòlèwaltìn katêkë}} ìpan inìn tlaìxmatkàtlàlilòtl.",
        "cancel": "Xiccāhua",
        "moredotdotdot": "Huehca ōmpa...",
        "mypage": "Noāmauh",
-       "mytalk": "Nozānīl",
+       "mytalk": "Teixnamiquiliztli",
        "anontalk": "Tēixnāmiquiliztli",
        "navigation": "Nēnemōhualiztli",
        "and": "&#32;īhuān",
        "unprotectthispage": "Xicpatla inīn tlaīxtli ītlapiyaliz",
        "newpage": "Yancuic tlaīxtli",
        "talkpage": "Xictlahto inīn tlaīxtli ītechcopa",
-       "talkpagelinktext": "Nenonotzaliztli",
+       "talkpagelinktext": "Teixnamiquiliztli",
        "specialpage": "Nònkuâkìskàtlaìxtlapalli",
        "personaltools": "In tlein nitēquitiltilia",
        "articlepage": "Xiquitta in tlamantlaīxtli",
        "disclaimers": "Nahuatīllahtōl",
        "edithelp": "Tlapatlaliztechcopa tēpalēhuiliztli",
        "helppage-top-gethelp": "Tēpalēhuiliztli",
-       "mainpage": "Huēyitlaīxtli",
+       "mainpage": "Yacatlahcuilolli",
        "mainpage-description": "Huēyitlaīxtli",
        "policy-url": "Project:Nahuatīltōn",
        "portal": "Calīxcuātl tocalpōl",
        "editlink": "xicpatla",
        "viewsourcelink": "xiquitta mēyalli",
        "editsectionhint": "Xicpatla in: $1",
-       "toc": "Inīn tlahcuilōlco",
+       "toc": "In tlein quipiya inin tlahcuilolli",
        "showtoc": "xicnēxti",
        "hidetoc": "xictlāti",
        "collapsible-collapse": "Motlàtìs",
        "site-atom-feed": "$1 Atom huelītiliztli",
        "page-rss-feed": "\"$1\" RSS huelītiliztli",
        "page-atom-feed": "\"$1\" RSS huelītiliztli",
-       "red-link-title": "$1 (ayāc in centlaīxtli)",
+       "red-link-title": "$1 (ahmo oncah tlahcuilolli)",
        "nstab-main": "Tlaīxtli",
        "nstab-user": "Tlatequitiltilīlli",
        "nstab-media": "Mēdiatl",
-       "nstab-special": "Nònkuâkìskàtlaìxtlapalli",
+       "nstab-special": "Noncuahquizqui tlahcuilolli",
        "nstab-project": "Ìtlaìxtlapal in tlayẻkàntekitl",
-       "nstab-image": "Ihcuilōlli",
+       "nstab-image": "Tlahcuilolpiyalli",
        "nstab-mediawiki": "Tlahcuilōltzintli",
        "nstab-template": "Nemachiòtl",
        "nstab-help": "Tèpalèwilistli",
        "nstab-category": "Tlaìxmatkàyòtlàlilòtl",
-       "mainpage-nstab": "Huēyitlaīxtli",
+       "mainpage-nstab": "Yacatlahcuilolli",
        "nosuchaction": "Ahmo ia tlachīhualiztli",
        "nosuchspecialpage": "Âmò ka inòn nònkuâkìskàtlaìxtlapalli",
        "nospecialpagetext": "<strong>Tiknẻki sè nònkuâkìskàtlaìxtlapalli tlèn âmò kä.</strong>\n\nKualli tikỉtas sè ìntlapòpòwaltekpànal in nònkuâkìskàtlaìxtlapaltìn ìpan [[Special:SpecialPages|{{int:specialpages}}]].",
        "welcomeuser": "Ximopanōlti, $1!",
        "yourname": "Tequihuihcātōcāitl:",
        "userlogin-yourname": "Tequihuihcātōcāitl",
+       "userlogin-yourname-ph": "Xiquihcuilo motoca iuhqui tequitihuani",
        "yourpassword": "Motlahtōlichtacāyo",
+       "userlogin-yourpassword": "Ichtacamachiyotl",
+       "createacct-yourpassword-ph": "Xictlali centetl ichtacamachiyotl",
        "yourpasswordagain": "Motlahtōlichtacāyo occeppa",
+       "createacct-yourpasswordagain": "Xicneltilia in ichtacamachiyotl",
+       "createacct-yourpasswordagain-ph": "Occepa xictlali in ichtacamachiyotl",
        "yourdomainname": "Moāxcāyō",
        "login": "Xicalaqui",
        "nav-login-createaccount": "Ximocalaqui / ximomachiyōmaca",
        "createaccount": "Xicchīhua tlapōhualli",
        "gotaccount": "¿Ye ticpiya cē tlapōhualli? '''$1'''.",
        "gotaccountlink": "Ximocalaqui",
+       "createacct-email-ph": "xiquihcuilo mocorreo electrónico",
        "createaccountmail": "Ticnemītīz ahmo cemihcac zāzoichtacātlahtōlli nō in tiquēhualtīz in maltzinteyōtl monetitlanizyeyān",
        "createaccountreason": "Tleīpampa:",
        "createacct-reason": "Tleīpampa",
        "pt-login": "Xicalaqui",
        "pt-login-button": "Xicalaqui",
        "pt-createaccount": "Xicchīhua motlapōhual",
+       "pt-userlogout": "Tiquizaz",
        "changepassword": "Xicpatla motlahtōlichtacāyo",
        "resetpass_header": "Xicpatla motlahtōlichtacāyo",
        "oldpassword": "Huēhueh motlahtōlichtacayo:",
        "revertmerge": "Tiquīxipehuaz",
        "history-title": "«$1» ītlaceppahuiliztlahtōllo",
        "lineno": "Pāntli $1:",
-       "editundo": "Tichuelōz",
+       "editundo": "Ticxitiniz",
        "searchresults": "Tlatēmoliztli",
        "searchresults-title": "«$1» tlatēmōliztli īmochīhualiz",
        "prevn": "{{PLURAL:$1|$1}} achtopa",
        "searchprofile-images-tooltip": "Tiquintēmōz tlahcuilōlli",
        "searchprofile-everything-tooltip": "Tictēmōz mochi tlapiyalizpan (mopiyah tēixnāmiquiliztli zāzanilli)",
        "search-result-size": "$1 ({{PLURAL:$2|1 tlahtōl|$2 tlahtōltin}})",
-       "search-redirect": "(tlacuepaliztli $1)",
+       "search-redirect": "(ixquichca ompa mitzhuica $1)",
        "search-section": "(tlahtōltzintli $1)",
        "search-category": "(tlaìxmatkàyòtlàlilòtl $1)",
        "search-suggest": "Ahnōceh tiquihtōznequiya: $1",
        "rcshowhidemine": "$1 notlahcuilōl",
        "rcshowhidemine-show": "Xicnēxti",
        "rclinks": "Xiquintta xōcoyōc $1 tlapatlaliztli xōcoyōc $2 tōnalpan.<br />$3",
-       "diff": "ahneneuh",
-       "hist": "tlahtōl",
+       "diff": "ahneneuhqui",
+       "hist": "tlahtollotl",
        "hide": "Tiquintlātīz",
        "show": "Xicnēxti",
        "minoreditletter": "p",
        "filehist-user": "Tequihuihqui",
        "filehist-dimensions": "Octacayōtl",
        "filehist-comment": "TlahtōIcaquiliztīlōni",
-       "imagelinks": "Ihcuilōlli ītequiuh",
+       "imagelinks": "In canin oquitlalihqueh",
        "linkstoimage": "Inīn {{PLURAL:$1|zāzanilli motzonhuilia|$1 zāzanilli motzonhuiliah}} inīn tlahcuilōlhuīc:",
        "nolinkstoimage": "Ahmo cateh zāzaniltin tlein tzonhuiliah inīn tlahcuilōlhuīc.",
        "morelinkstoimage": "Tiquinttāz [[Special:WhatLinksHere/$1|achi tzonhuiliztli]] inīn tlahcuilōlhuīc.",
        "blanknamespace": "(Huēyi)",
        "contributions": "In {{GENDER:$1|tlatequitiltilīlli}} ītlahcuilōl",
        "contributions-title": "Tlatequitiltilīlli $1 ītlahcuilōl",
-       "mycontris": "Notlahcuilōl",
+       "mycontris": "Notlahcuilol",
        "contribsub2": "$1 ($2)",
        "uctop": "(āxcān tlapatlaliztli)",
        "month": "Īhuīcpa mētztli (auh achtopa):",
        "tooltip-ca-watch": "Ticcēntilīz inīn zāzanilli motlachiyalizhuīc",
        "tooltip-ca-unwatch": "Ahtictlachiyāz inīn zāzanilli",
        "tooltip-search": "Tlatēmōz īpan {{SITENAME}}",
-       "tooltip-search-go": "Tiyaz in zāzanilhuīc īca inīn huel melāhuac tōcaitl intlā yez",
+       "tooltip-search-go": "Tiyaz ihuicpa tlahcuilolli ica inin huel melahuac tocaitl intla oncah",
        "tooltip-search-fulltext": "Tictemōz inīn tlahcuilōlli in āmac",
        "tooltip-p-logo": "Xiquitta in tohuēyitlaīx",
-       "tooltip-n-mainpage": "Tiquittaz in huēyitlaīxtli",
+       "tooltip-n-mainpage": "Tiquittaz in yacatlahcuilolli",
        "tooltip-n-mainpage-description": "Xiquitta in tohuēyitlaīx",
        "tooltip-n-portal": "Tlachīhualiztechcopa, inōn tihuelīti titlachīhua, tlatēmoyān",
        "tooltip-n-recentchanges": "Yancuic īpan tlapatlaliztli in huiqui",
        "fileduplicatesearch-filename": "Tlahcuilōlli ītōcā:",
        "fileduplicatesearch-submit": "Tlatēmōz",
        "fileduplicatesearch-info": "$1 × $2 pixelli<br />Tlahcuilōlli īxquichiliz: $3<br />MIME iuhcāyōtl: $4",
-       "specialpages": "Nònkuâkìskàtlaìxtlapaltìn",
+       "specialpages": "Noncuahquizqui tlahcuilolli",
        "specialpages-note": "* Yeliztli nōncuahquīzqui āmatl.\n* <span class=\"mw-specialpagerestricted\">Tlaquīxtīlli nōncuahquīzqui āmatl.</span>\n* <span class=\"mw-specialpagecached\">Tlatlātīlli nōncuahquīzqui āmatl (aocmo monemitīa).</span>",
        "specialpages-group-other": "Oksẻki nònkuâkìskàtlaìxtlapaltìn",
        "specialpages-group-login": "Ximocalaqui / ximomachiyōmaca",
        "htmlform-selectorother-other": "Occē",
        "rightsnone": "ahtlein",
        "revdelete-summary": "ticpatlāz tlahcuilōltōn",
-       "searchsuggest-search": "Mà motèmo",
+       "searchsuggest-search": "Tlatemoliztli",
        "api-error-ok-but-empty": "Tlâtek îtlakawilistli: Âmò tènankilia in tlatèmakani.",
        "api-error-overwrite": "Awel motlâkuilnepanòltis sè èwalli tlèn yi katki.",
        "api-error-stashfailed": "Tlâtek îtlakawilistli: In tlatèmakani awel òkeuh in èwalpanòni.",
index c72ae68..b46c21b 100644 (file)
        "nextrevision": "Khah-sin ê siu-tēng-pún→",
        "currentrevisionlink": "khoàⁿ siōng sin ê siu-tēng-pún",
        "cur": "taⁿ",
-       "next": "下一个",
+       "next": "āu",
        "last": "chêng",
        "page_first": "Tùi thâu-chêng",
        "page_last": "Tùi āu-piah",
        "tag-list-wrapper": "([[Special:Tags|$1 ê piau-chhiam]]: $2)",
        "logentry-move-move": "$1 {{GENDER:$2|sóa}} $3 chit ia̍h khì $4",
        "logentry-newusers-create": "已經{{GENDER:$2|開好}}用者口座 $1",
-       "searchsuggest-search": "Chhoē",
+       "searchsuggest-search": "Chhoē {{SITENAME}}",
        "expandtemplates": "Khok-chhiong pang-bô͘",
        "expand_templates_input": "Su-ji̍p bûn-jī:",
        "expand_templates_output": "Kiat-kó:",
index d403668..f356b98 100644 (file)
        "versionrequired": "MediaWiki-versjon $1 er påkrevd",
        "versionrequiredtext": "MediaWiki-versjon $1 er nødvendig for å bruke denne siden. Se [[Special:Version|versjonsiden]]",
        "ok": "OK",
+       "pagetitle": "$1 – {{SITENAME}}",
        "retrievedfrom": "Hentet fra «$1»",
        "youhavenewmessages": "Du har $1 ($2).",
        "youhavenewmessagesfromusers": "Du har $1 fra {{PLURAL:$3|en annen bruker| $3 brukere}} ($2).",
index f475dbc..e156e10 100644 (file)
        "mycustomcssprotected": "यो CSSपृष्ठ सम्पादन गर्नको लागि लागि तपाईंलाई अनुमति छैन ।",
        "mycustomjsprotected": "यो जावास्क्रिप्ट पृष्ठ सम्पादन गर्नको लागि तपाईंलाई अनुमति छैन ।",
        "myprivateinfoprotected": "तपाईँसँग तपाईँको निजी जानकारीहरू सम्पादन गर्ने अनुमती छैन",
-       "mypreferencesprotected": "तपाà¤\88à¤\81सà¤\81à¤\97 à¤¤à¤ªà¤¾à¤\88à¤\81को अभिरुचीहरू सम्पादन गर्ने अनुमती छैन",
+       "mypreferencesprotected": "तपाà¤\88à¤\82सà¤\81à¤\97 à¤¤à¤ªà¤¾à¤\88à¤\82को अभिरुचीहरू सम्पादन गर्ने अनुमती छैन",
        "ns-specialprotected": "विशेष पृष्ठहरू सम्पादन गर्न सकिदैन।",
        "titleprotected": "[[User:$1|$1]]द्वारा यो शीर्षक निर्माणहुनबाट जोगाइएको छ।\nकारण <em>$2</em> हो ।",
        "filereadonlyerror": "फाइल \"$1\" लाई परिवर्तन गर्न सकिँदैन किन भने फाइल भण्डार  \"$2\" केवल पढ्ने स्थिति (read-only mode)मा छ।\n\nयसलाई सुरक्षित गर्ने प्रवन्धकले  यो कारण दिएकाछन् : ''$3''।",
        "createacct-error": "खाता बनाउँदा त्रुटि",
        "createaccounterror": "खाता बनाउन सकिएन: $1",
        "nocookiesnew": "तपाईंको खाता बनाइयो, तर तपाईं प्रवेश गर्नुभएको छैन ।\n{{SITENAME}} ले प्रयोगकर्ता प्रवेश गराउन कुकीहरू प्रयोग गर्छ ।\nतपाईंका कुकीहरू निस्क्रिय छन् ।\nकृपया सक्रिय बनाइ , नाम र प्रवेशशब्द राखी प्रवेश गर्नुहोला ।",
-       "nocookieslogin": "{{SITENAME}} ले प्रयोगकर्ता प्रवेश गराउन कुकीहरू प्रयोग गर्छ । तपाईँको कुकीहरू निस्क्रिय गरिएको छ। कृपया सक्रिय बनाइ , नाम र प्रवेशशव्द राखी प्रवेश गर्नुहोला ।",
+       "nocookieslogin": "{{SITENAME}} ले प्रयोगकर्ता प्रवेश गराउन कुकीहरू प्रयोग गर्छ। तपाईंको कुकीहरू निष्कृय गरिएको छ। कृपया सक्रिय बनाइ पुन प्रवेश गर्नुहोला।",
        "nocookiesfornew": "प्रयोगकर्ताको खाता निर्माण गरिएन, हामीले यसको मूल स्रोत निर्धारण गर्न सकेनौं।\nनिश्चित गर्नुहोस् तपाईंले कुकी सक्रिय गर्नुभएको छ, पुनः यस पृष्ठलाई खोल्ने प्रयास गर्नुहोस्।",
        "nocookiesforlogin": "{{int:nocookieslogin}}",
        "noname": "तपाईंले सही प्रयोगकर्ता नाम दिनु भएन।",
        "noemailcreate": "तपाईंले सही ई-मेल ठेगाना दिनुपर्छ",
        "passwordsent": "\"$1\" को लागि दर्ता गरिएको ई-मेल ठेगानामा एक प्रवेशशव्द पठाइएको छ।\nकृपया त्यसलाई प्राप्त गरेपछि प्रवेश गर्नुहोला ।",
        "blocked-mailpassword": "तपाईंको IP ठेगानालाई सम्पादनगर्नबाट रोक लगाइएको छ, र त्यसैले दुरुपयोग रोक्नको लागि प्रवेसशब्द पुनर्लाभ प्रक्रिया प्रयोग गर्न अनुमति छैन ।",
-       "eauthentsent": "दिà¤\87à¤\8fà¤\95à¥\8b à¤\87मà¥\87ल à¤ à¥\87à¤\97ानामा à¤\87मà¥\87ल à¤ªà¤ à¤¾à¤\87à¤\8fà¤\95à¥\8b à¤\9b à¥¤\nतपाà¤\88à¤\81à¤\95à¥\8b à¤\96ातामा à¤\85रà¥\81 à¤\87मà¥\87ल à¤ªà¤ à¤\89नà¥\81 à¤\85à¤\98ि , à¤\87मà¥\87लमा à¤²à¥\87à¤\96िà¤\8fà¤\95à¥\8b à¤®à¤¾à¤°à¥\8dà¤\97दरà¥\8dशन à¤\85नà¥\81सार , à¤¤à¥\8dयà¥\8b à¤\96ाता à¤¤à¤ªà¤¾à¤\88à¤\81कै हो भनेर निश्चित गर्नु पर्नेछ ।",
+       "eauthentsent": "दिà¤\87à¤\8fà¤\95à¥\8b à¤\87मà¥\87ल à¤ à¥\87à¤\97ानामा à¤\87मà¥\87ल à¤ªà¤ à¤¾à¤\87à¤\8fà¤\95à¥\8b à¤\9b à¥¤\nतपाà¤\88à¤\82à¤\95à¥\8b à¤\96ातामा à¤\85रà¥\81 à¤\87मà¥\87ल à¤ªà¤ à¤\89नà¥\81 à¤\85à¤\98ि , à¤\87मà¥\87लमा à¤²à¥\87à¤\96िà¤\8fà¤\95à¥\8b à¤®à¤¾à¤°à¥\8dà¤\97दरà¥\8dशन à¤\85नà¥\81सार , à¤¤à¥\8dयà¥\8b à¤\96ाता à¤¤à¤ªà¤¾à¤\88à¤\82कै हो भनेर निश्चित गर्नु पर्नेछ ।",
        "throttled-mailpassword": "बितेको {{PLURAL:$1|घण्टा|$1 घण्टाहरु}} भित्र एउटा पासवर्ड अनुस्मारक पठाई सकिएको छ।\nदुरुपयोगबाट बचाउकोलागि प्रत्येक {{PLURAL:$1|घण्टा|$1 घण्टाहरु}}मा केवल एउटा पासवर्ड अनुस्मारक पठाइन्छ।",
        "mailerror": " चिठी :$1 पठाउँदा त्रुटी भयो",
        "acct_creation_throttle_hit": "तपाईंको आईपी ठेगानाबाट आएका आगन्तुकद्वारा बितेको चौबिस घण्टामा यस विकिमा {{PLURAL:$1|एउटा खाता बनाइसकिएको छ|$1 खाताहरु बनाइसकिएका छन्}}, यस समयावधिमा यति नैं अधिकतम सीमा हो।\nअतः यस समय यस आईपी ठेगानाको प्रयोग गर्ने आगन्तुकले अरु खाता खोल्न सक्नेछैनन्।",
        "action-sendemail": "इमेलहरु पठाउने",
        "action-editmywatchlist": "तपाईँको निगरानी सुची सम्पादन गर्नुहोस",
        "action-viewmywatchlist": "तपाईँको निगरानी सुची हेर्नुहोस",
-       "action-viewmyprivateinfo": "तपाà¤\88à¤\81को व्यक्तिगत जानकारी हेर्नुहोस",
+       "action-viewmyprivateinfo": "तपाà¤\88à¤\82को व्यक्तिगत जानकारी हेर्नुहोस",
        "action-editmyprivateinfo": "तपाईँको व्यक्तिगत जानकारी सम्पादन गर्नुहोस",
        "action-editcontentmodel": "पृष्ठको सामग्री नमुना सम्पादन",
        "action-managechangetags": "डाटाबेसबाट ट्यागहरू बनाउने र मेटाउने",
        "emailmessage": "सन्देश:",
        "emailsend": "पठाउनुहोस्",
        "emailccme": "मेरो सन्देशको एउटा प्रति मलाई ई-मेल गरिदिनुहोस्।",
-       "emailccsubject": "तपाà¤\88à¤\81को सन्देशको प्रतिलिपि  $1: $2लाई",
+       "emailccsubject": "तपाà¤\88à¤\82को सन्देशको प्रतिलिपि  $1: $2लाई",
        "emailsent": "इमेल पठाईयो",
        "emailsenttext": "तपाईंको ई-मेल सन्देश पठाइयो।",
        "emailuserfooter": "यो ईमेल $1 ले $2 लाई \"ई-मेल प्रयोगकर्ता\" कार्यानुरुप {{SITENAME}}मा पठाएको थियो।",
index 417110e..b92995c 100644 (file)
        "newarticle": "(Ny)",
        "newarticletext": "Du har følgt ei lenkje til ei side som ikkje finst enno.\nFor å opprette sida, kan du skrive i boksen under (sjå [$1 hjelpesida] for meir informasjon).\nHamna du her ved ein feil, klikk på '''attende'''-knappen i nettlesaren din.",
        "anontalkpagetext": "----''Dette er ei diskusjonsside for ein anonym brukar som ikkje har oppretta konto eller ikkje har logga inn.\nVi er difor nøydde til å bruke den numeriske IP-adressa til å identifisere brukaren. Same IP-adresse kan vere knytt til fleire brukarar. Om du er ein anonym brukar og meiner at du har fått irrelevante kommentarar på ei slik side, [[Special:CreateAccount|opprett ein brukarkonto]] eller [[Special:UserLogin|logg inn]] slik at vi unngår framtidige forvekslingar med andre anonyme brukarar.''",
-       "noarticletext": "Det er nett no ikkje noko tekst på denne sida.\nDu kan [[Special:Search/{{PAGENAME}}|søkja etter sidetittelen]] i andre sider, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søkja i dei relaterte loggane]\neller [{{fullurl:{{FULLPAGENAME}}|action=edit}} endra denne sida]</span>.",
+       "noarticletext": "Det er nett no ikkje noko tekst på denne sida.\nDu kan [[Special:Search/{{PAGENAME}}|søkja etter sidetittelen]] i andre sider, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søkja i dei relaterte loggane]\neller [{{fullurl:{{FULLPAGENAME}}|action=edit}} opprette denne sida]</span>.",
        "noarticletext-nopermission": "Der er nett no ikkje noko tekst på denne sida.\nDu kan [[Special:Search/{{PAGENAME}}|søkja etter sidetittelen]] i andre sider\neller <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} søkja i dei relaterte loggane]</span>, men du har ikkje løyve til å oppretta denne sida.",
        "missing-revision": "Versjonen #$1 av sida med namnet «{{FULLPAGENAME}}» finst ikkje.\n\nDette skriv seg som oftast frå at ei forelda historikklenkje vart fylgd til ei side som er sletta.\nDetaljar kan ein finna i [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} sletteloggen].",
        "userpage-userdoesnotexist": "Brukarkontoen «<nowiki>$1</nowiki>» finst ikkje. Vil du verkeleg opprette/endre denne sida?",
        "searchprofile-advanced-tooltip": "Søk i visse namnerom",
        "search-result-size": "$1 ({{PLURAL:$2|eitt|$2}} ord)",
        "search-result-category-size": "{{PLURAL:$1|1 medlem|$1 medlemmer}} ({{PLURAL:$2|1 underkategori|$2 underkategoriar}}, {{PLURAL:$3|1 fil|$3 filer}})",
-       "search-redirect": "(omdirigering $1)",
+       "search-redirect": "(omdirigering frå $1)",
        "search-section": "(bolken $1)",
        "search-category": "(kategorien $1)",
        "search-suggest": "Meinte du: «$1»",
        "feedback-subject": "Emne:",
        "feedback-submit": "Send",
        "feedback-thanks": "Takk! Attendemeldinga di er lagd inn på sida «[$2 $1]».",
-       "searchsuggest-search": "Søk",
+       "searchsuggest-search": "Søk i {{SITENAME}}",
        "searchsuggest-containing": "som inneheld …",
        "api-error-badaccess-groups": "Du har ikkje løyve til å lasta opp filer til wikien.",
        "api-error-badtoken": "Intern feil: ugild token.",
index 2886de1..b0c0efb 100644 (file)
        "newimages-showbots": "Pokaż pliki przesłane przez boty",
        "newimages-hidepatrolled": "Ukryj sprawdzone pliki",
        "noimages": "Brak plików do pokazania.",
+       "gallery-slideshow-toggle": "Przełączanie miniatur",
        "ilsubmit": "Szukaj",
        "bydate": "według daty",
        "sp-newimages-showfrom": "pokaż nowe pliki począwszy od $2, $1",
        "feedback-thanks": "Dziękujemy! Twoja opinia została opublikowana na stronie \"[$2 $1]\".",
        "feedback-thanks-title": "Dziękujemy!",
        "feedback-useragent": "Aplikacja klienta:",
-       "searchsuggest-search": "Szukaj",
+       "searchsuggest-search": "Przeszukaj {{GRAMMAR:B.lp|{{SITENAME}}}}",
        "searchsuggest-containing": "zawierające...",
        "api-error-autoblocked": "Twój adres IP został automatycznie zablokowany, ponieważ był używany przez zablokowanego użytkownika.",
        "api-error-badaccess-groups": "Nie masz uprawnień aby przesyłać pliki do tej wiki.",
        "linkaccounts-submit": "Połącz konta",
        "unlinkaccounts": "Odłącz konta",
        "unlinkaccounts-success": "Konta zostały odłączone.",
+       "userjsispublic": "Uwaga: Podstrony z kodem JavaScript są widoczne publicznie i nie powinny zawierać poufnych danych.",
+       "usercssispublic": "Uwaga: Podstrony z kodem CSS są widoczne publicznie i nie powinny zawierać poufnych danych.",
        "restrictionsfield-badip": "Nieprawidłowy adres IP lub zakres adresów: $1",
        "restrictionsfield-label": "Dozwolone zakresy adresów IP:",
-       "restrictionsfield-help": "Jeden adres IP lub zakres CIDR w wierszu. Aby zaznaczyć wszystkie, użyj<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "Jeden adres IP lub zakres CIDR w wierszu. Aby zaznaczyć wszystkie, użyj<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Błąd: $1",
+       "edit-error-long": "Błędy:\n\n$1"
 }
index ddd47e8..8442125 100644 (file)
        "revdelete-confirm": "Por favor, confirme que pretende executar esta operação, que compreende as suas consequências e que o faz em concordância com as [[{{MediaWiki:Policy-url}}|políticas e recomendações]].",
        "revdelete-suppress-text": "A supressão '''só''' deverá ser usada nos seguintes casos:\n* Informação potencialmente caluniosa, difamatória ou injuriosa\n* Informação pessoal imprópria\n*: ''endereços de domicílio e números de telefone, números de identificação nacional, etc''",
        "revdelete-legend": "Definir restrições de visibilidade",
-       "revdelete-hide-text": "Revisão do texto",
+       "revdelete-hide-text": "Texto da revisão",
        "revdelete-hide-image": "Ocultar conteúdo do ficheiro",
        "revdelete-hide-name": "Ocultar destino e parâmetros",
        "revdelete-hide-comment": "Resumo da edição",
-       "revdelete-hide-user": "Nome de utilizador/endereço de IP",
+       "revdelete-hide-user": "Nome de utilizador/endereço IP",
        "revdelete-hide-restricted": "Ocultar dados dos administradores e de todos os outros",
        "revdelete-radio-same": "(manter)",
        "revdelete-radio-set": "Oculto",
        "movelogpagetext": "Abaixo encontra-se uma lista de páginas movidas.",
        "movesubpage": "{{PLURAL:$1|Subpágina|Subpáginas}}",
        "movesubpagetext": "Esta página tem $1 {{PLURAL:$1|subpágina mostrada|subpáginas mostradas}} abaixo.",
+       "movesubpagetalktext": "A página de discussão correspondente tem $1 {{PLURAL:$1|subpágina|subpáginas}}, mostradas abaixo.",
        "movenosubpage": "Esta página não tem subpáginas.",
        "movereason": "Motivo:",
        "revertmove": "reverter",
        "version-license-not-found": "Não foi encontrada informação detalhada da licença para esta extensão.",
        "version-credits-title": "Créditos de autoria da extensão $1",
        "version-credits-not-found": "Não foi encontrada informação detalhada dos créditos para esta extensão.",
-       "version-poweredby-credits": "Este é um wiki <strong>[https://www.mediawiki.org/ MediaWiki]</strong>, copyright © 2001-$1 $2.",
+       "version-poweredby-credits": "Esta é uma wiki <strong>[https://www.mediawiki.org/ MediaWiki]</strong>, copyright © 2001-$1 $2.",
        "version-poweredby-others": "outros",
        "version-poweredby-translators": "os tradutores da translatewiki.net",
        "version-credits-summary": "Gostaríamos de reconhecer as seguintes pessoas pela sua contribuição para o [[Special:Version|MediaWiki]].",
        "version-libraries-description": "Descrição",
        "version-libraries-authors": "Autores",
        "redirect": "Redirecionar por ficheiro, utilizador, página, revisão, ou ID de registo",
-       "redirect-summary": "Esta página especial redireciona para um ficheiro (dado o nome do ficheiro), para uma página (dado um ID de revisão ou página) ou para uma página de utilizador (dado um ID numérico do utilizador), ou para uma entrada do registo (dado o ID do registo). Utilização: [[{{#Special:Redirect}}/file/Example.jpg]], \n[[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], ou [[{{#Special:Redirect}}/logid/186]].",
+       "redirect-summary": "Esta página especial redireciona para um ficheiro (dado o nome do ficheiro), para uma página (dado um ID de revisão ou página), para uma página de utilizador (dado um ID numérico do utilizador) ou para uma entrada do registo (dado o ID do registo). Utilização: [[{{#Special:Redirect}}/file/Example.jpg]], \n[[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], ou [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Ir",
        "redirect-lookup": "Pesquisa:",
        "redirect-value": "Valor:",
        "usercssispublic": "Nota: As subpáginas de CSS não devem conter dados confidenciais porque podem ser vistas por outros utilizadores.",
        "restrictionsfield-badip": "Endereço IP (ou gama de endereços IP) inválido: $1",
        "restrictionsfield-label": "Gamas de endereços IP permitidas:",
-       "restrictionsfield-help": "Um endereço IP ou uma gama CIDR por linha. Para ativar todos,\nuse<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "Um endereço IP ou uma gama CIDR por linha. Para ativar todos,\nuse<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Erro: $1",
+       "edit-error-long": "Erros:\n\n$1"
 }
index 235bf1e..a934741 100644 (file)
        "movepage-max-pages": "PROBABLY (A GUESS): when moving a page, you can select an option of moving its subpages, but there is a maximum that can be moved automatically.\n\nParameters:\n* $1 - maximum moved pages, defined in the variable [[mw:Special:MyLanguage/Manual:$wgMaximumMovedPages|$wgMaximumMovedPages]]",
        "movelogpage": "{{doc-logpage}}\n\nTitle of [[Special:Log/move]]. Used as heading on that page, and in the dropdown menu on log pages.",
        "movelogpagetext": "Text on the special page 'Move log'.",
-       "movesubpage": "This is a section header on [[Special:MovePage]], below is a list of subpages.\n\nParameters:\n* $1 - number of subpages\nSee also:\n* {{msg-mw|movenosubpage|without subpage}}\n* {{msg-mw|movesubpagetext|with subpages}}",
-       "movesubpagetext": "Used in [[Special:MovePage]]. Parameters:\n* $1 - number of subpages\nSee also:\n* {{msg-mw|movesubpage|section header}}\n* {{msg-mw|movenosubpage|without subpage}}",
-       "movenosubpage": "See also:\n* {{msg-mw|movesubpage|section header}}\n* {{msg-mw|movenosubpage|without subpage}}\n* {{msg-mw|movesubpagetext|with subpages}}",
+       "movesubpage": "This is a section header on [[Special:MovePage]], below is a list of subpages.\n\nParameters:\n* $1 - number of subpages\nSee also:\n* {{msg-mw|movenosubpage|without subpage}}\n* {{msg-mw|movesubpagetext|with subpages}}\n* {{msg-mw|movesubpagetalktext|with talk subpages}}",
+       "movesubpagetext": "Used in [[Special:MovePage]]. Parameters:\n* $1 - number of subpages\nSee also:\n* {{msg-mw|movesubpage|section header}}\n* {{msg-mw|movenosubpage|without subpage}}\n* {{msg-mw|movesubpagetalktext|with talk subpages}}",
+       "movesubpagetalktext": "Used in [[Special:MovePage]] when corresponding talk page has subpages. Parameters:\n* $1 - number of subpages\nSee also:\n* {{msg-mw|movesubpage|section header}}\n* {{msg-mw|movenosubpage|without subpage}}",
+       "movenosubpage": "See also:\n* {{msg-mw|movesubpage|section header}}\n* {{msg-mw|movenosubpage|without subpage}}\n* {{msg-mw|movesubpagetext|with subpages}}\n* {{msg-mw|movesubpagetalktext|with talk subpages}}",
        "movereason": "Used in [[Special:MovePage]]. The text for the inputbox to give a reason for the page move.\n\nSee also:\n* {{msg-mw|Move-page-legend|legend for the form}}\n* {{msg-mw|newtitle|label for new title}}\n* {{msg-mw|Movetalk|label for checkbox}}\n* {{msg-mw|Move-leave-redirect|label for checkbox}}\n* {{msg-mw|Fix-double-redirects|label for checkbox}}\n* {{msg-mw|Move-subpages|label for checkbox}}\n* {{msg-mw|Move-talk-subpages|label for checkbox}}\n* {{msg-mw|Move-watch|label for checkbox}}\n{{Identical|Reason}}",
        "move-redirect-text": "{{ignored}}The text that's added to a redirected page when that redirect is created.",
        "category-move-redirect-override": "{{ignored}}The text that's added to a redirected category page when that redirect is created.",
        "feedback-thanks": "Thanks message, appears if feedback was successful. Parameters:\n* $1 - \"Feedback\"\n* $2 - Feedback page URL",
        "feedback-thanks-title": "The title of the thank you dialog at the end of the submission process.\n{{Identical|Thank you}}",
        "feedback-useragent": "A label denoting the user agent in the feedback that is posted to the feedback page.\n{{Identical|User agent}}",
-       "searchsuggest-search": "Greyed out default text in the simple search box in the Vector skin. (It disappears and lets the user enter the requested search terms when the search box receives focus.)",
+       "searchsuggest-search": "Greyed out default text in the simple search box in the Vector skin. (It disappears and lets the user enter the requested search terms when the search box receives focus.)\n{{Identical|Search}}",
        "searchsuggest-containing": "Label used in the special item of the search suggestions list which gives the user an option to perform a full text search for the term.",
        "api-error-autoblocked": "API error message that can be used for client side localisation of API errors.\n\nCf. {{msg-mw|Autoblockedtext}}.",
        "api-error-badaccess-groups": "API error message that can be used for client side localisation of API errors.",
        "usercssispublic": "A reminder to users that CSS subpages are not preferences but normal pages, and thus can be viewed by other users and the general public. This message is shown to a user whenever they are editing a subpage in their own user-space that ends in .css. See also {{msg-mw|userjsispublic}}",
        "restrictionsfield-badip": "An error message shown when one entered an invalid IP address or range in a restrictions field (such as Special:BotPassword). $1 is the IP address.",
        "restrictionsfield-label": "Field label shown for restriction fields (e.g. on Special:BotPassword).",
-       "restrictionsfield-help": "Placeholder text displayed in restriction fields (e.g. on Special:BotPassword)."
+       "restrictionsfield-help": "Placeholder text displayed in restriction fields (e.g. on Special:BotPassword).",
+       "edit-error-short": "Error message. Parameters:\n* $1 - the error details\nSee also:\n* {{msg-mw|edit-error-long}}\n{{Identical|Error}}",
+       "edit-error-long": "Error message. Parameters:\n* $1 - the error details\nSee also:\n* {{msg-mw|edit-error-short}}\n{{Identical|Error}}"
 }
index 5cce849..d113101 100644 (file)
        "recreate": "Recreează",
        "confirm_purge_button": "OK",
        "confirm-purge-top": "Doriți să reîncărcați pagina?",
-       "confirm-purge-bottom": "Actualizaea unei pagini șterge cache-ul și forțează cea mai recentă variantă să apară.",
+       "confirm-purge-bottom": "Actualizarea unei pagini șterge cache-ul și forțează cea mai recentă variantă să apară.",
        "confirm-watch-button": "OK",
        "confirm-watch-top": "Adăugați această pagină la lista de pagini urmărite?",
        "confirm-unwatch-button": "OK",
index 23c7739..7b3be92 100644 (file)
        "movelogpagetext": "Ниже представлен список переименованных страниц.",
        "movesubpage": "{{PLURAL:$1|1=Подстраница|Подстраницы}}",
        "movesubpagetext": "У этой страницы $1 {{PLURAL:$1|подстраница|подстраницы|подстраниц}}.",
+       "movesubpagetalktext": "У соответствующей страницы обсуждения есть $1 {{PLURAL:$1|подстраница, показанная |подстраниц, показанных|подстраницы, показанные}} ниже.",
        "movenosubpage": "У этой страницы нет подстраниц.",
        "movereason": "Причина:",
        "revertmove": "возврат",
        "newimages-showbots": "Показать загрузки ботов",
        "newimages-hidepatrolled": "Скрыть отпатрулированные загрузки",
        "noimages": "Изображения отсутствуют.",
+       "gallery-slideshow-toggle": "Переключить миниатюры",
        "ilsubmit": "Найти",
        "bydate": "по дате",
        "sp-newimages-showfrom": "Показать новые файлы, начиная с $2, $1",
        "feedback-thanks": "Спасибо! Ваш отзыв размещён на странице «[$2 $1]».",
        "feedback-thanks-title": "Спасибо!",
        "feedback-useragent": "Браузер:",
-       "searchsuggest-search": "Ð\9fоиÑ\81к",
+       "searchsuggest-search": "Ð\98Ñ\81каÑ\82Ñ\8c Ð² {{grammar:prepositional|{{SITENAME}}}}",
        "searchsuggest-containing": "содержащие…",
        "api-error-autoblocked": "Ваш IP-адрес был автоматически заблокирован, потому что он был использован заблокированным участником.",
        "api-error-badaccess-groups": "Вам не разрешено загружать файлы в эту вики.",
        "usercssispublic": "Обратите внимание: подстраницы CSS не должны содержать конфиденциальные сведения, поскольку они доступны для просмотра другим участникам.",
        "restrictionsfield-badip": "Недопустимый IP-адрес или диапазон адресов: $1",
        "restrictionsfield-label": "Разрешённые диапазоны IP-адресов:",
-       "restrictionsfield-help": "По одному IP-адресу или CIDR-диапазону в строке. Чтобы разрешить всё, используйте <br /><code>0.0.0.0/0</code><br /><code>::/0</code>"
+       "restrictionsfield-help": "По одному IP-адресу или CIDR-диапазону в строке. Чтобы разрешить всё, используйте <br /><code>0.0.0.0/0</code><br /><code>::/0</code>",
+       "edit-error-short": "Ошибка: $1",
+       "edit-error-long": "Ошибки: $1"
 }
index bf9746d..57d178e 100644 (file)
        "tog-showtoolbar": "سنوار اوزار ڏيکاريو",
        "tog-editondblclick": "ٻٽي ڪلڪ تي صفحا سنواريو",
        "tog-watchcreations": "منهنجا سرجيل صفحا ۽ منهنجا چاڙهيل فائيل منهنجي زيرِ نظر فهرست تي رکو",
-       "tog-watchdefault": "منهنجا ترميميل صفحا ۽ فائيل  منهنجي زير نظر فهرست تي رکو",
-       "tog-watchmoves": "جيڪي صفحا ۽ فائيل آءُٗ چوريان، سي منهنجي زير نظر فهرست ۾ شامل ڪريو.",
-       "tog-watchdeletion": "آءُٗ جيڪي صفحا ۽ فائيل  ڊاهيان، سي منهنجي زير نظر فهرست تي رکو",
-       "tog-watchrollback": "انهن صفحن کي منهنجي زير نظر فهرست تي رکو، جن ۾ تبديلين کي مون واپس ورايو آهي.",
+       "tog-watchdefault": "منهنجا ترميميل صفحا ۽ فائيل  منهنجي نظرھيٺ فھرست ۾ رکو",
+       "tog-watchmoves": "جيڪي صفحا ۽ فائيل آءُٗ چوريان، سي منهنجي نظرھيٺ فھرست ۾ شامل ڪريو.",
+       "tog-watchdeletion": "آءُٗ جيڪي صفحا ۽ فائيل  ڊاهيان، سي منهنجي نظرھيٺ فھرست تي رکو",
+       "tog-watchrollback": "انهن صفحن کي منهنجي نظرھيٺ فھرست تي رکو، جن ۾ تبديلين کي مون واپس ورايو آهي.",
        "tog-minordefault": "سمورين تبديلين کي بنان چئي معمولي ترميم تصور ڪريو",
-       "tog-previewontop": "ترÙ\85Ù\8aÙ\85Ù\8a Ø¨Ø§ÚªØ³ Ù\85ٿاÙ\86 Ù¾Ù\8aØ´ Ù\86گاÙ\87Û\81 ڏيکاريو",
-       "tog-previewonfirst": "پهرين ترميم تي پيش نگاهہ ڏيکاريو",
-       "tog-enotifwatchlistpages": "مونکي ايميل ڪريو جڏهن منهنجي زير نظر فهرست ڪا صفحو يا فائيل تبديل ڪيو وڃي",
+       "tog-previewontop": "ترÙ\85Ù\8aÙ\85Ù\8a Ø¯Ù»Ù\8a Ù\85ٿاÙ\86 Ù¾Ù\8aØ´ Ù\86گاھ ڏيکاريو",
+       "tog-previewonfirst": "پهرين ترميم تي پيش نگاھ ڏيکاريو",
+       "tog-enotifwatchlistpages": "مون کي ايميل ڪريو جڏهن منهنجي نظرھيٺ فھرست ۾ ڪو صفحو يا فائيل تبديل ڪيو وڃي",
        "tog-enotifusertalkpages": "منهنجي مباحثي صفحي ۾ تبديليءَ جي صورت ۾ مون کي برق ٽپال اماڻيو",
        "tog-enotifminoredits": "صفحن ۾ معمولي ترميمن جي صورت ۾ بہ مون کي برق ٽپال ڪريو",
        "tog-enotifrevealaddr": "پڌراين ۾ منهنجو برق ٽپال پتو ظاهر ڪريو.",
        "tog-shownumberswatching": "ڏسندڙ يوزرس جو انگ ڏيکاريو",
        "tog-oldsig": "توھان جو موجوده دستخط:",
+       "tog-fancysig": "صحيح کي وڪيٽيڪسٽ سمجھو (ڪنھن خوڪار ڳنڍڻي کانسواءِ)",
        "tog-uselivepreview": "سڌي سنئين پيش نگاھہ استعمال ڪريو",
        "tog-watchlisthideown": "زير نظر فهرست مان منهنجون ڪيل ترميمون لڪايو",
        "tog-watchlisthidebots": "ٽيٽ فهرست تان بوٽ جون ترميمون لڪايو",
        "tog-watchlisthideminor": "ٽيٽ فهرست تان معمولي ترميمون لڪايو",
        "tog-watchlisthideliu": "لاگ اِن ٿيل يوزرس جون ڪيل ترميمون زيرنظر فهرست ۾ نہ ڏيکاريو",
        "tog-watchlisthideanons": "ٽيٽ فهرست تان اڻڄاتل يوزر جون ترميمون لڪايو",
+       "tog-watchlisthidepatrolled": "نظرھيٺ فھرست مان گشت ڪيل ترميمون لڪايو",
        "tog-watchlisthidecategorization": "صفحن جا زمرا لڪايو",
        "tog-ccmeonemails": "ٻين يوزرس ڏانهن منهنجي موڪليل برق ٽپال جو پرت مون کي اماڻيو",
        "tog-diffonly": "تفاوت هيٺان صفحي جو مواد نہ ڏيکاريو",
@@ -67,8 +69,8 @@
        "march": "مارچ",
        "april": "اپريل",
        "may_long": "مَئي",
-       "june": "جÙ\8fÙ\88Ù\86Ù\90",
-       "july": "جÙ\8fÙ\88Ù\84اءÙ\90",
+       "june": "جÙ\88Ù\86",
+       "july": "جولاءِ",
        "august": "آگسٽ",
        "september": "سيپٽمبر",
        "october": "آڪٽوبر",
@@ -80,7 +82,7 @@
        "april-gen": "اپريل",
        "may-gen": "مَئي",
        "june-gen": "جُونِ",
-       "july-gen": "جÙ\8fÙ\88Ù\84اءÙ\90",
+       "july-gen": "جولاءِ",
        "august-gen": "آگسٽ",
        "september-gen": "سيپٽمبر",
        "october-gen": "آڪٽوبر",
@@ -90,9 +92,9 @@
        "feb": "فيبروري",
        "mar": "مارچ",
        "apr": "اپريل",
-       "may": "مَئي",
-       "jun": "جÙ\8fÙ\88Ù\86Ù\90",
-       "jul": "جÙ\8fÙ\88Ù\84اءÙ\90",
+       "may": "مئي",
+       "jun": "جÙ\88Ù\86",
+       "jul": "جولاءِ",
        "aug": "آگسٽ",
        "sep": "سيپٽمبر",
        "oct": "آڪٽوبر",
        "august-date": "آگسٽ $1",
        "september-date": "سيپٽمبر $1",
        "october-date": "آڪٽوبر $1",
-       "november-date": "Ù\86Ù\8eÙ\88Ù\90مبر $1",
+       "november-date": "Ù\86Ù\88مبر $1",
        "december-date": "ڊسمبر $1",
        "period-am": "صبح جو",
        "period-pm": "منجھند کان بعد",
        "category-article-count-limited": "هيٺِون {{PLURAL:$1|صفحو آهي|$1 صفحا آهن}} تازي زمري ۾.",
        "category-file-count": "{{PLURAL:$2|هن زمري ۾ صرف هيٺيون فائيل آهي.|هيٺيون يا هيٺيان {{PLURAL:$1|فائيل آهي|$1 فائيل آهن}} هن زمري ۾، سمورن $2 مان.}}",
        "category-file-count-limited": "هيٺيون يا هيٺيان {{PLURAL:$1|فائيل آهي|$1 فائيل آهن}} هن تازي زمري ۾.",
-       "listingcontinuesabbrev": "جاري..",
+       "listingcontinuesabbrev": "جاري.",
        "index-category": "ڏسڻيل صفحا",
-       "noindex-category": "غير-ڏسڻيل صفحا",
+       "noindex-category": "غيرڏسڻيل صفحا",
        "broken-file-category": "فائيل جي ٽٽل ڳنڍڻن وارا صفحا",
        "about": "بابت",
        "article": "موادي صفحو",
        "moredotdotdot": "اڃا...",
        "morenotlisted": "ھي فھرست نامڪمل بہ ٿي سگھي ٿي.",
        "mypage": "منهنجو صفحو",
-       "mytalk": "ڳالهہ ٻول",
-       "anontalk": "ڳالھ ٻولھ",
+       "mytalk": "بحث",
+       "anontalk": "بحث",
        "navigation": "رهنمائي",
        "and": "&#32؛۽",
        "qbfind": "ڳوليو",
        "faq": "ڪپس",
        "faqpage": "Project:ڪپوس",
        "actions": "فعل",
-       "namespaces": "نانءُ پولار:",
+       "namespaces": "نانءُپولارَ",
        "variants": "بَدَلَ",
        "navigation-heading": "رهنما مينيو",
        "errorpagetitle": "چُڪَ",
        "search": "ڳولا",
        "searchbutton": "ڳوليو",
        "go": "کوليو",
-       "searcharticle": "کوليو",
+       "searcharticle": "وڃو",
        "history": "صفحي جي سوانح",
        "history_short": "سوانح",
        "printableversion": "ڇپائتو پرت",
        "permalink": "مسقتل ڳنڍڻو",
        "print": "ڇاپيو",
-       "view": "نگاهہ",
+       "view": "ڏسو",
        "view-foreign": "$1 تي ڏسو",
        "edit": "سنواريو",
        "edit-local": "مقامي تشريح کي ترميميو",
        "talk": "بحث",
        "views": "ڏيٺون",
        "toolbox": "اوزارَ",
+       "tool-link-userrights": "{{GENDER:$1|يوزر}} گروھ تبديل ڪريو",
+       "tool-link-emailuser": "ھن {{GENDER:$1|يوزر}} ڏانھن برقٽپال موڪليو",
        "userpage": "يوزر صفحو ڏسو",
        "projectpage": "رٿائي صفحو ڏسو",
        "imagepage": "ذريعاتي صفحو ڏسو",
        "otherlanguages": "ٻين ٻولين ۾",
        "redirectedfrom": "($1 کان چوريل)",
        "redirectpagesub": "چوريل صفحو",
-       "redirectto": "ڏانهن چوريو",
+       "redirectto": "ڏانھن چوريو:",
        "lastmodifiedat": "هيءُ صفحو آخري دفعو $2، $1ع تي سنواريو ويو هو.",
        "viewcount": "هيءُ صفحو {{PLURAL:$1|دفعو|$1 دفعا}} ڏسجي چڪو آهي.",
        "protectedpage": "تحفظيل صفحو",
-       "jumpto": "ڏانهن ٽپ ڏيو",
+       "jumpto": "ڏانھن ٽپ ڏيو:",
        "jumptonavigation": "رهنمائي",
        "jumptosearch": "ڳولا",
+       "view-pool-error": "معذرت سان سرور هاڻي تمام گھڻو سُڪ آهي.\nتمام گھڻا يوزر ھن صفحي کي ڏسڻ جي ڪوشش ڪري رھيا آھن.\nمهرباني ڪري ٿورو ترسو انکان اڳ جو توھان ھن صفحي تائين رسڻ لاءِ ٻيھر ڪوشش ڪريو.\n\n$1",
        "generic-pool-error": "معذرت سان سرور هاڻي تمام گھڻو سُڪ آهي.\nتمام گھڻا يوزر هتي موجود آهن.\nمهرباني ڪري ٿورو ترسي پوءِ ڪوشش ڪريو.",
        "pool-errorunknown": "اڻ ڄاتل چُڪَ",
        "poolcounter-usage-error": "استعمال جي خرابي: $1",
        "copyright": "ڪجھہ ٻيو ڄاڻايل نہ هجڻ جي صورت ۾ سمورو مواد $1 تحت ميسر ڪجي ٿو.",
        "copyrightpage": "{{ns:project}}:حق ۽ واسطا",
        "currentevents": "ھاڻوڪا واقعا",
-       "currentevents-url": "Project: اعداد",
+       "currentevents-url": "Project:ھاڻوڪا واقعا",
        "disclaimers": "غيرجوابداريناما",
        "disclaimerpage": "Project:عام غيرجوابدارينامو",
        "edithelp": "مدد براءِ ترميم",
        "helppage-top-gethelp": "مدد",
-       "mainpage": "مُک صفحو",
-       "mainpage-description": "مُک صفحو",
+       "mainpage": "مک صفحو",
+       "mainpage-description": "مک صفحو",
        "policy-url": "Project:پاليسي",
        "portal": "نياتي باب",
        "portal-url": "Project:نياتي باب",
        "retrievedfrom": "\"$1\" تان ورتل",
        "youhavenewmessages": "توهان لاءِ $1 ($2) آهن.",
        "youhavenewmessagesmanyusers": "توهان لاءِ ڪيترن ئي يُوزرس ($2) طرفان $1 آيل آهن.",
+       "newmessageslinkplural": "{{PLURAL:$1|ھڪ نئون پيغام|999=نوان پيغام}}",
+       "newmessagesdifflinkplural": "آخري {{PLURAL:$1|تبديلي|999=تبديليون}}",
        "youhavenewmessagesmulti": "$1 تي توهان لاءِ نوان نياپا آهن",
        "editsection": "سنواريو",
        "editold": "سنواريو",
        "editlink": "سنواريو",
        "viewsourcelink": "ڪوڊ ڏسو",
        "editsectionhint": "سنواريو سيڪشن: $1",
-       "toc": "فهرست",
+       "toc": "فھرست",
        "showtoc": "ڏيکاريو",
        "hidetoc": "لڪايو",
        "collapsible-collapse": "بند ڪريو",
        "site-atom-feed": "$1 اڻو روان رسد",
        "page-rss-feed": "\"$1\" RSS برق مواد",
        "page-atom-feed": "\"$1\" اڻو روان رسد",
-       "red-link-title": "$1 (صفحو وجود نہ ٿو رکي)",
+       "red-link-title": "$1 (صفحو وجود نٿو رکي)",
        "sort-descending": "لهندڙ ترتيب ڏيو",
        "sort-ascending": "چڙهندڙ ترتيب ڏيو",
        "nstab-main": "صفحو",
        "databaseerror-query": "استفسار: $1",
        "databaseerror-function": "ڪاڄ: $1",
        "databaseerror-error": "چُڪَ: $1",
+       "laggedslavemode": "<strong>چتاءُ:</strong> صفحي ۾ ھاڻوڪيون تبديليون نه ھجڻ جو امڪان آھي.",
        "readonly": "اعدادخانو بنديل",
        "missingarticle-rev": "(ڀيرو#: $1)",
        "missingarticle-diff": "(تفاوت: $1، $2)",
        "mypreferencesprotected": "توهان جي پنهنجون ترجيحات سنوارڻ جي اجات حاصل ڪانهي.",
        "ns-specialprotected": "خاص صفحا سنواري نٿا سگھجن.",
        "titleprotected": "[[User:$1|$1]] اهڙي عنوان سان صفحو سرجڻ تي روڪ لڳائي ڇڏي آهي. سبب <em>$2</em> ڄاڻايو ويو آهي.",
-       "exception-nologin": "لا اِن ٿيل ناهيو",
+       "exception-nologin": "داخل ٿيل ناهيو",
        "virus-unknownscanner": "اڻ ڄاتل نِس وائرس:",
-       "cannotlogoutnow-title": "ھاڻÙ\8a Ù\84اگ Ø¢Ø¦Ù\88Ù½ Ù\86Ù¿Ù\88 ڪري سگھجي",
-       "cannotlogoutnow-text": "$1 Ø§Ø³ØªØ¹Ù\85اÙ\84 ÚªØ±Ú» Ø¯Ù\88راÙ\86 Ù\84اگ Ø¢Ø¦Ù\88Ù½ ڪرڻ ممڪن نہ آھي.",
+       "cannotlogoutnow-title": "ھاڻÙ\8a Ù»Ø§Ú¾Ø± Ù\86Ù¿Ù\88 Ù\86ڪري سگھجي",
+       "cannotlogoutnow-text": "$1 Ø§Ø³ØªØ¹Ù\85اÙ\84 ÚªØ±Ú» Ø¯Ù\88راÙ\86 Ù»Ø§Ú¾Ø± Ù\86ڪرڻ ممڪن نہ آھي.",
        "welcomeuser": "ڀلي ڪري آيا، $1!",
        "yourname": "يُوزرنانءُ:",
        "userlogin-yourname": "يوزرنانءُ",
        "userlogin-yourname-ph": "پنهنجو يوزرنانءُ ڄاڻايو",
        "createacct-another-username-ph": "يُوزرنانءُ ڄاڻايو",
-       "yourpassword": "ڳجھو لفظ:",
-       "userlogin-yourpassword": "ڳجھو لفظ",
-       "userlogin-yourpassword-ph": "پنهنجو ڳجھو لفظ ڄاڻايو",
-       "createacct-yourpassword-ph": "ڳجھو لفظ ڄاڻايو",
+       "yourpassword": "ڳجھولفظ:",
+       "userlogin-yourpassword": "ڳجھولفظ",
+       "userlogin-yourpassword-ph": "پنهنجو ڳجھولفظ ڄاڻايو",
+       "createacct-yourpassword-ph": "ڳجھولفظ ڄاڻايو",
        "yourpasswordagain": "يُوزرنان ٻيهر ٽائيپ ڪريو:",
        "createacct-yourpasswordagain": "ڳجھي لفظ جي خاطري ڪريو",
-       "createacct-yourpasswordagain-ph": "ٻيهر ڳجھو لفظ داخل ڪريو",
-       "userlogin-remembermypassword": "مون کي لاگ اِن رکو",
+       "createacct-yourpasswordagain-ph": "ٻيھر ڳجھولفظ داخل ڪريو",
+       "userlogin-remembermypassword": "مون کي داخل ٿيل رکو",
        "userlogin-signwithsecure": "محفوظ ڳانڍاپو استعمال ڪريو",
-       "cannotloginnow-title": "ھاڻي لاگ ان نٿو ڪري سگھجي",
-       "cannotloginnow-text": "$1 استعمال ڪرڻ دوران لاگ ان ڪرڻ ممڪن نہ آھي.",
+       "cannotlogin-title": "داخل نٿو ٿي سگھجي",
+       "cannotlogin-text": "داخل ٿيڻ ممڪن نه آھي",
+       "cannotloginnow-title": "ھاڻي داخل نٿو ٿي سگھجي",
+       "cannotloginnow-text": "$1 استعمال ڪرڻ دوران داخل ٿيڻ ممڪن نہ آھي.",
+       "cannotcreateaccount-title": "کاتا نٿو کولي سگھي",
        "yourdomainname": "توهان جو ميدان:",
-       "password-change-forbidden": "هن وڪِي تي توهان ڳجھو لفظ بدلائي نہ ٿا سگھو.",
-       "login": "لاگ اِن",
-       "nav-login-createaccount": "لاگ اِن ٿيو / کاتو کوليو",
-       "userlogin": "لاگ اِن ٿيو / کاتو کوليو",
-       "userloginnocreate": "لاگ اِن",
-       "logout": "لاگ آئوٽ",
-       "userlogout": "لاگ آئوٽ",
-       "notloggedin": "لاگ اِن ٿيل ناهيو",
-       "userlogin-noaccount": "کاتو نہ ٿا رکو؟",
+       "password-change-forbidden": "هن وڪِي تي توهان ڳجھالفظ بدلائي نٿا سگھو.",
+       "login": "داخل ٿيو",
+       "login-security": "پنھنجي سڃاڻپ جي خاطري ڪريو",
+       "nav-login-createaccount": "داخل ٿيو / کاتو کوليو",
+       "userlogin": "داخل ٿيو / کاتو کوليو",
+       "userloginnocreate": "داخل ٿيو",
+       "logout": "ٻاھر نڪرو",
+       "userlogout": "ٻاھر نڪرو",
+       "notloggedin": "داخل ٿيل ناهيو",
+       "userlogin-noaccount": "کاتو نٿا رکو؟",
        "userlogin-joinproject": "{{SITENAME}} ۾ شامل ٿيو",
        "nologin": " کاتو نہ ٿا رکو؟ '''$1'''.",
        "nologinlink": "نئون کاتو کوليو",
        "createaccount": "کاتو کوليو",
        "gotaccount": "ڇا اڳي ئي کاتو رکو ٿا؟ '''$1'''.",
-       "gotaccountlink": "لاگ اِن",
-       "userlogin-resetlink": "پنهنجي لاگ اِن جا تفصيل وساري ويٺا؟",
-       "userlogin-resetpassword-link": "ڳجھو لفظ وساري ويٺا آهيو؟",
-       "userlogin-helplink2": "لاگ اِن ٿيڻ ۾ مدد",
+       "gotaccountlink": "داخل ٿيو",
+       "userlogin-resetlink": "پنهنجي داخل ٿيڻ جا تفصيل وساري ويٺا؟",
+       "userlogin-resetpassword-link": "ڳجھولفظ وساري ويٺا آهيو؟",
+       "userlogin-helplink2": "داخل ٿيڻ ۾ مدد",
+       "userlogin-reauth": "اھو پڪ ڪرڻ لاءِ ته توھان {{GENDER:$1|$1}} آھيو توھان کي ٻيھر داخل ٿيڻو پوندو.",
        "userlogin-createanother": "ٻيو کاتو کوليو",
        "createacct-emailrequired": "برق ٽپال پتو",
        "createacct-emailoptional": "برق ٽپال پتو (مرضيءَ موجب)",
        "createacct-reason-ph": "توهان ٻيو کاتو ڇو کولي رهيا آهيو",
        "createacct-submit": "پنهنجو کاتو کوليو",
        "createacct-another-submit": "کاتو کوليو",
+       "createacct-continue-submit": "کاتو کولڻ جاري رکو",
+       "createacct-another-continue-submit": "کاتو کولڻ جاري رکو",
        "createacct-benefit-heading": "{{SITENAME}} توهان جهڙن سڄڻن ٺاهيو آهي.",
        "createacct-benefit-body1": "{{PLURAL:$1|ترميم|ترميمون}}",
        "createacct-benefit-body2": "{{PLURAL:$1|صفحو|صفحا}}",
        "createacct-benefit-body3": "حاليه {{PLURAL:$1|ڀاڱيدار}}",
-       "badretype": "توهان جو ڄاڻايل ڳجھو لفظ درست نہ آهي.",
+       "badretype": "توهان جو ڄاڻايل ڳجھولفظ درست نہ آهي.",
        "usernameinprogress": "ان يُوزرنانءُ لاءِ کاتو اڳ ۾ ئي تياريءَ هيٺ آهي. مهرباني ڪري انتظار فرمايو.",
        "userexists": "ڄاڻايل يوزرنانءُ اڳ ۾ ئي استعمال هيٺ آهي. مهرباني ڪري ڪو ٻيو يُوزرنانءُ چونڊيو.",
-       "loginerror": "لاگ اِن چُڪَ",
+       "loginerror": "داخل ٿيڻ ۾ چُڪَ",
        "createacct-error": "کاٿو کولڻ ۾ چُڪَ",
        "createaccounterror": "کاتو کُلي نہ سگھيو: $1",
-       "nocookiesnew": "يُوزر کاتو کلي چڪو، پر توهان لاگ اِن نہ ٿيا آهيو. يُوزرس کي لاگ اِن ڪرڻ لاءِ {{SITENAME}} ڪوڪيز استعمال ڪندي آهي. توهان ڪوڪيز کي ناڪاره بڻائي رکيو آهي. لاگ اِن ٿيڻ لاءِ ڪوڪيز کي ڪارائتو بڻايو.",
+       "nocookiesnew": "يُوزر کاتو کلي چڪو، پر توهان داخل نہ ٿيا آهيو. يُوزرس کي داخل ڪرڻ لاءِ {{SITENAME}} ڪوڪيز استعمال ڪندي آهي. توهان ڪوڪيز کي ناڪاره بڻائي رکيو آهي. داخل ٿيڻ لاءِ ڪوڪيز کي ڪارائتو بڻايو.",
        "nocookieslogin": "يُوزرس کي لاگ اِن ڪرڻ لاءِ {{SITENAME}} ڪوڪيز استعمال ڪندي آهي. توهان ڪوڪيز کي ناڪاره بڻائي رکيو آهي. لاگ اِن ٿيڻ لاءِ ڪوڪيز کي ڪارائتو بڻايو.",
        "noname": "توهان جو ڄاڻايل يُوزرنانءُ ناقابل ڪار آهي.",
-       "loginsuccesstitle": "لاگ اِن ٿيل",
-       "loginsuccess": "'''هاڻي توهان {{SITENAME}} تي بطور \"$1\" لاگ اِن ٿيل آهيو.'''",
+       "loginsuccesstitle": "داخل ٿيل",
+       "loginsuccess": "'''هاڻي توهان {{SITENAME}} تي بطور \"$1\" داخل ٿيل آهيو.'''",
        "nosuchuser": "\"$1\" نالي سان ڪو بہ يوزر نہ آهي.\nننڍن وڏن اکرن ۾ امتياز ڪرڻ لازمي آهي. \nهِجي چڪاسيو، يا [[Special:CreateAccount|نئون کاتو تخليق ڪريو]]",
        "nosuchusershort": "\"$1\" نالي ڪو بہ يُوزر ناهي.\nهِجي جي پڪ ڪندا.",
        "nouserspecified": "توهان کي ڪو يوزرنانءُ ڄاڻائڻو پوندو.",
-       "login-userblocked": "هيءُ يُوزر بندشيل آهي. لاگ اِن جي اجازت نہ ٿي ڏجي.",
-       "wrongpassword": "ڏنل ڳجھو لفظ غير درست آهي. مهرباني ڪري ٻيهر ڪوشش ڪندا.",
-       "wrongpasswordempty": "ڏنل ڳجھو لفظ خالي هو. مهرباني ڪري وري ڪوشش ڪندا.",
-       "passwordtooshort": "ڳجھÙ\8a لفظ گھٽ ۾ گھٽ  {{PLURAL:$1|1 اکر|$1 اکرَن}} تي ٻڌل هوڻ گھرجي.",
-       "passwordtoolong": "ڳجھو لفظ {{PLURAL:$1|1 اکر|$1 اکرن}} کان وڏو نہ ٿو ٿي سگھي.",
-       "password-name-match": "توهان جو ڳجھو لفظ توهان جي يوزرنانءُ کان مختلف هجڻ گھرجي.",
-       "mailmypassword": "ڳجھو لفظ  نئين سِر مقرر ڪريو",
-       "passwordremindertitle": "{{SITENAME}} لاءِ نئون عارضي ڳجھو لفظ",
+       "login-userblocked": "هيءُ يُوزر بندشيل آهي. داخل ٿيڻ جي اجازت نٿي ڏجي.",
+       "wrongpassword": "ڏنل ڳجھولفظ غير درست آهي. مھرباني ڪري ٻيھر ڪوشش ڪندا.",
+       "wrongpasswordempty": "ڏنل ڳجھولفظ خالي هو.\nمهرباني ڪري وري ڪوشش ڪندا.",
+       "passwordtooshort": "ڳجھÙ\88لفظ گھٽ ۾ گھٽ  {{PLURAL:$1|1 اکر|$1 اکرَن}} تي ٻڌل هوڻ گھرجي.",
+       "passwordtoolong": "ڳجھولفظ {{PLURAL:$1|1 اکر|$1 اکرن}} کان وڏو نٿو ٿي سگھي.",
+       "password-name-match": "توهان جو ڳجھولفظ توهان جي يوزرنانءُ کان مختلف هجڻ گھرجي.",
+       "mailmypassword": "ڳجھولفظ ٻيھر مقرر ڪريو",
+       "passwordremindertitle": "{{SITENAME}} لاءِ نئون عارضي ڳجھولفظ",
        "passwordremindertext": "ڪنهن (شايد توهان آءِ پي پتي $1 تان) اسان کي {{SITENAME}} ($4) لاءِ نئون ڳجھو لفظ اماڻڻ جي گھُرَ ڪئي.\"$2\" يوزر لاءِ هڪ ڳجھُ لفظ تخليق ڪيو ويو آهي \"$3\" تي ترتيب ڏنو ويو هو. جيڪڏهن اهو توهان جي ارادو هيو، ته هاڻي توهان کي هينئر ئي لاگ اِن ٿي پنهنجو ڳجھو لفظ تبديل ڪرڻ گھرجي.\nتوهان جو عارضي ڳجھو لفظ {{PLURAL:$5|هڪ ڏينهُن|$5 ڏينهَن}} ۾ ختم ٿيندو.\n\nجيڪڏهن اها گھُرَ اوهان نه ڪئي هئي، يا هاڻي اوهان کي پنهنجو ڳجھو لفظ ياد اچي ويو آهي ۽ توهان ان کي تبديل ڪرڻ نه ٿا چاهيو، ته توهان هن نياپي کي نظر انداز ڪندي پنهنجو پراڻو ڳجھو لفظ ئي استعمال ڪري سگھو ٿا.",
        "noemail": "يُوزر \"$1\" جي ڪو بہ برق ٽپال پتو درج ٿيل ناهي.",
        "noemailcreate": "توهان کي قابل ڪار برق ٽپال پتو مهيا ڪرڻو پوندو.",
        "accountcreated": "کاتو کلي چڪو",
        "accountcreatedtext": "يوزر کاتو [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|talk]]) جي لاءِ تخليق ٿي چڪو آهي.",
        "createaccount-title": "{{SITENAME}} تي کاتو کولڻ",
-       "login-throttled": "توهان تازو ئي لاگ اِن ٿيڻ جون هيڪانديون گھڻيون ڪوششون ڪيون آهن. مهرباني ڪري $1 لاءِ ترسي پوءِ وري ڪوشش ڪريو.",
+       "login-throttled": "توهان تازو ئي داخل ٿيڻ جون هيڪانديون گھڻيون ڪوششون ڪيون آهن. مهرباني ڪري $1 لاءِ ترسي پوءِ وري ڪوشش ڪريو.",
        "login-abort-generic": "توهان جو داخل ٿيڻ ناڪام ويو - بند ڪيل",
        "login-migrated-generic": "توهان جو کاتو لڏي چڪو آهي، ۽ هن وڪيءَ تي توهان جو يُوزنانءُ هاڻي وجود نہ ٿو رکي.",
        "loginlanguagelabel": "ٻولي: $1",
        "createacct-another-realname-tip": "اصل نالو ڄاڻائڻ اختياري آهي. جيڪڏهن توهان اصل نالو ڄاڻايو ٿا، تہ اهو توهان کي توهان جي ڪم جي مڃتا ڏيڻ لاءِ ڪم آندو ويندو.",
-       "pt-login": "لاگ ان ٿيو",
-       "pt-login-button": "لاگ اِن",
+       "pt-login": "داخل ٿيو",
+       "pt-login-button": "داخل ٿيو",
+       "pt-login-continue-button": "داخل ٿيڻ جاري رکو",
        "pt-createaccount": "کاتو کوليو",
-       "pt-userlogout": "Ù\84اگ Ø¢Ø¦Ù\88Ù½",
+       "pt-userlogout": "ٻاھر Ù\86ڪرÙ\88",
        "php-mail-error-unknown": "پي ايڇ پي جي  ڪاڄ اندر اڻڄاتل چُڪَ.",
        "user-mail-no-addy": "برق ٽپال پتو ڄاڻائڻ کان سواءِ برق ٽپال اماڻڻ جي ڪوشش ڪئي وئي.",
-       "changepassword": "ڳجھو لفظ تبديل ڪريو",
-       "resetpass_announce": "لاگ اِن جو عمل پورو ڪرڻ لاءِ، توهان کي نئون ڳجھو لفظ اختيار مقرر ڪرڻو پوندو.",
-       "resetpass_header": "کاتي جو ڳجھو لفظ بدلايو",
-       "oldpassword": "اڳوڻو ڳجھو لفظ:",
-       "newpassword": "نئون ڳجھو لفظ:",
-       "retypenew": "نئون ڳجھو لفظ ٻيهر ٽائيپ ڪندا:",
-       "resetpass_submit": "ڳجھو لفظ طَي ڪريو ۽ لاگ اِن ٿيو",
+       "changepassword": "ڳجھولفظ تبديل ڪريو",
+       "resetpass_announce": "داخل ٿيڻ جو عمل پورو ڪرڻ لاءِ، توهان کي نئون ڳجھولفظ اختيار مقرر ڪرڻو پوندو.",
+       "resetpass_header": "کاتي جو ڳجھولفظ بدلايو",
+       "oldpassword": "اڳوڻو ڳجھولفظ:",
+       "newpassword": "نئون ڳجھولفظ:",
+       "retypenew": "نئون ڳجھولفظ ٻيهر ٽائيپ ڪندا:",
+       "resetpass_submit": "ڳجھولفظ طَي ڪريو ۽ داخل ٿيو",
        "changepassword-success": "توهان جو ڳجھولفظ بدلايو ويو آھي!",
-       "changepassword-throttled": "توهان تازو ئي لاگ اِن ٿيڻ جون هيڪانديون گھڻيون ڪوششون ڪيون آهن. مهرباني ڪري $1 لاءِ ترسي پوءِ وري ڪوشش ڪريو.",
+       "changepassword-throttled": "توهان تازو ئي داخل ٿيڻ جون هيڪانديون گھڻيون ڪوششون ڪيون آهن. مهرباني ڪري $1 لاءِ ترسي پوءِ وري ڪوشش ڪريو.",
        "botpasswords-label-create": "سرجيو",
        "botpasswords-label-update": "تجديد",
        "botpasswords-label-cancel": "رد",
        "botpasswords-label-delete": "ڊاهيو",
-       "botpasswords-label-resetpassword": "ڳجھو لفظ  نئين سِر مقرر ڪريو",
-       "resetpass_forbidden": "ڳجھو لفظ بدلائي نہ ٿو سگھجي.",
-       "resetpass-no-info": "هيءُ صفحو پڙهڻ لاءِ لاگ اِن ٿيڻ ضروري آهي.",
-       "resetpass-submit-loggedin": "ڳجھو لفظ بدلايو",
+       "botpasswords-label-resetpassword": "ڳجھولفظ ٻيھر مقرر ڪريو",
+       "resetpass_forbidden": "ڳجھالفظ بدلائي نٿا سگھجن",
+       "resetpass-no-info": "هيءُ صفحو پڙهڻ لاءِ داخل ٿيڻ ضروري آهي.",
+       "resetpass-submit-loggedin": "ڳجھولفظ بدلايو",
        "resetpass-submit-cancel": "رد",
        "resetpass-wrong-oldpass": "ناقابل ڪار هاڻوڪو يا عارضي ڳجھولفظ. \nتوهان پنهنجو ڳجھو لفظ اڳ ۾ ئي بدلائي چڪا آهيو يا نئين ڳجھي لفظ لاءِ درخواست ڏئي چڪا آهيو.",
        "resetpass-recycled": "مهرباني ڪري پنهنجي هاڻوڪي ڳجھي لفظ کان ڪو مختلف ڳجھو لفظ چونڊيو.",
        "resetpass-temp-emailed": "توهان برق ٽپال ذريعي اماڻيل عارضي ڳجھي لفظ سان لاگ اِن ٿيا آهيو. لاگ اِن کي مڪمل ڪرڻ لاءِ توهان کي هتي نئون ڳجھو لفظ طَي ڪرڻو ئي پوندو:",
-       "resetpass-temp-password": "عارضي ڳجھو لفظ:",
-       "resetpass-expired": "توهان جو ڳجھو لفظ مدي خارج ٿي چڪو آهي. نئون ڳجھو لفظ مقرر ڪريو ۽ لاگ اِن ٿيو.",
+       "resetpass-temp-password": "عارضي ڳجھولفظ:",
+       "resetpass-expired": "توهان جو ڳجھولفظ مدي خارج ٿي چڪو آهي. نئون ڳجھولفظ مقرر ڪريو ۽ داخل ٿيو.",
        "resetpass-expired-soft": "توهان جو ڳجھو لفظ مدي خارج ٿي چڪو آهي. مهرباني ڪري نئون ڳجھو لفظ چونڊيو، يا ساڳيو ڪم ڪنهن ٻي وقت ڪرڻ لاءِ \"{{int:authprovider-resetpass-skip-label}}\" تي ڪلڪ ڪريو.",
-       "resetpass-validity-soft": "توهان جو ڳجھو لفظ ناقابل ڪار آهي: $1\nمهرباني ڪري نئون ڳجھو لفظ چونڊيو، يا ساڳيو ڪم ڪنهن ٻي وقت ڪرڻ لاءِ \"{{int:authprovider-resetpass-skip-label}}\" تي ڪلڪ ڪريو.",
-       "passwordreset": "ڳجھو لفظ مَٽايو",
-       "passwordreset-text-one": "برق ٽپال ذريعي عارضي ڳجھو لفظ حاصل ڪرڻ لاءِ هيءُ فارم پُر ڪريو.",
-       "passwordreset-disabled": "هن وڪيءَ تي ڳجھو لفظ نئين سِر مقرر ڪرڻ وارو چارو غير فعال بڻايو ويو آهي.",
+       "resetpass-validity-soft": "توهان جو ڳجھولفظ ناقابل ڪار آهي: $1\nمهرباني ڪري نئون ڳجھولفظ چونڊيو، يا ساڳيو ڪم ڪنهن ٻي وقت ڪرڻ لاءِ \"{{int:authprovider-resetpass-skip-label}}\" تي ڪلڪ ڪريو.",
+       "passwordreset": "ڳجھولفظ مَٽايو",
+       "passwordreset-text-one": "برق ٽپال ذريعي عارضي ڳجھولفظ حاصل ڪرڻ لاءِ هيءُ فارم پُر ڪريو.",
+       "passwordreset-disabled": "هن وڪيءَ تي ڳجھولفظ ٻيھر مقرر ڪرڻ وارو چارو غير فعال بڻايو ويو آهي.",
        "passwordreset-emaildisabled": "هن وڪيءَ تي برق‌ٽپال واريون خصوصيتون غير فعال بڻايون ويون آهن.",
        "passwordreset-username": "يُوزرنانءُ:",
        "passwordreset-domain": "ميدان:",
        "minoredit": "هيءَ هڪ معمولي ترميم آهي",
        "watchthis": "هيءُ صفحو سانڍيو",
        "savearticle": "صفحو سانڍيو",
-       "preview": "پيش نگاهہ",
-       "showpreview": "پيش نگاهہ",
+       "savechanges": "تبديليون سانڍيو",
+       "publishpage": "صفحو ڇاپيو",
+       "publishchanges": "تبديليون ڇاپيو",
+       "preview": "پيش نگاھ",
+       "showpreview": "پيش نگاھ",
        "showdiff": "تبديليون ڏيکاريو",
-       "anoneditwarning": "<strong>خبردار:</strong> توهان لاگ اِن ٿيل نہ آهيو. جيڪڏهن توهان ڪي ترميمون ڪيون تہ هن صفحي جي سوانح ۾ توهان جو آءِ پي پتو درج ڪيو ويندو. جي توهان <strong>[$1 لاگ اِن]</strong> ٿيو ٿا <strong>[$2 کاتو کوليو] </strong> ٿا، تہ توهان جو ترميمون توهان جي يوزرنانءُ سن منسوب ڪيون وينديون، جنهن جا ٻيا بہ فائدا ٿي سگھن ٿا.",
-       "anonpreviewwarning": "توهان لاگ اِن ٿيل نہ آهيو. جيڪڏهن توهان صفحي ۾ تبديليون سانڍيون تہ اهڙين تبديلين ساڻ توهان جو آءِ پي پتو درج ڪيو ويندو.",
+       "anoneditwarning": "<strong>خبردار:</strong> توهان داخل ٿيل نہ آهيو. جيڪڏهن توهان ڪي ترميمون ڪيون تہ هن صفحي جي سوانح ۾ توهان جو آءِ پي پتو درج ڪيو ويندو. جي توهان <strong>[$1 داخل]</strong> ٿيو ٿا < يا strong>[$2 کاتو کوليو] </strong> ٿا، تہ توهان جو ترميمون توهان جي يوزرنانءُ سن منسوب ڪيون وينديون، جنهن جا ٻيا بہ فائدا ٿي سگھن ٿا.",
+       "anonpreviewwarning": "توهان داخل ٿيل نہ آهيو. جيڪڏهن توهان صفحي ۾ تبديليون سانڍيون تہ اهڙين تبديلين ساڻ توهان جو آءِپي پتو درج ڪيو ويندو.",
        "missingcommenttext": "براءِ مهرباني هيٺ پنهنجا تاثرات درج ڪندا.",
-       "summary-preview": "تت تي پيش نگاهہ:",
-       "subject-preview": "موضوع پيش نگاهہ:",
+       "summary-preview": "تت تي پيش نگاھ:",
+       "subject-preview": "موضوع پيش نگاھ:",
        "blockedtitle": "يُوزر بندشيل آهي.",
        "blockedtext": "'''توهان جي يوزرنانءُ يا آءِ پي کي بندشيو ويو آهي.'''\n\nبندش $1 هنئي. جڏهن تہ ڄاڻايل سبب ''$2'' آهي.\n\n\n* بندش جو آغاز: $8\n* بندش جو انجام: $6\n* بندش جو هدف: $7\n\nاهڙي روڪ تي بحث ڪرڻ لاءِ توهان $1 يا ڪنهن ٻي [[{{MediaWiki:Grouppage-sysop}}|منتظم]] سان رابطو ڪري سگھو ٿا. جيڪڏهن توهان جو درست [[Special:ترجيحات|کاتو ترجيحات]] ۾ درست برق ٽپال پتو درج ٿيل نہ آهي تہ توهان 'هن يوزر کي برق ٽپال ڪريو' وارو فيچر نہ ٿا \nYou cannot use the 'e-mail this user' feature unless a valid e-mail address is specified in your [[Special:Preferences|account preferences]] and you have not been blocked from using it.\nاستعمال ڪري سگھو. توهان جو هاڻوڪو آءِ پي پتو $3 آهي، ۽ بندش سڃاڻپ $5 آهي. مهرباني ڪري ڪنهن بہ پڇا ڳاڇا يا لهوچڙ لاءِ انهن مان ڪنهن هڪ يا ٻنهي جو حوالو ڏيندا.",
        "blockednoreason": "سبب اڻڄاڻايل",
        "whitelistedittext": "صفحا سنوارڻ لاءِ مهرباني ڪري $1.",
        "confirmedittext": "صفحا سنوارڻ کان اڳ توهان کي پنهنجي ايميل پتي جي تصديق ڪرڻي پوندي. مهرباني ڪري [[Special:Preferences|use preferences]] ذريعي پنهنجو ايميل پتو ڄاڻايو ۽ تصديقيو.",
        "nosuchsectiontitle": "سيڪشن نٿو لهي سگهي",
-       "loginreqtitle": "لاگ اِن گھربل آهي",
-       "loginreqlink": "لاگ اِن",
+       "loginreqtitle": "داخل ٿيڻ گھربل آهي",
+       "loginreqlink": "داخل ٿيو",
        "loginreqpagetext": "ٻيا صفحا ڏسڻ لاءِ مهرباني ڪري $1",
-       "accmailtitle": "ڳجھو لفظ اماڻجي چڪو.",
+       "accmailtitle": "ڳجھولفظ اماڻجي چڪو",
        "newarticle": "(نئون)",
-       "newarticletext": "توهان اهڙي صفحي جو ڳنڍڻو وٺي هتي پهتا آهيو، جيڪو اڃا وجود نہ ٿو رکي. اهڙو صفحو جوڙڻ لاءِ هيٺين باڪس ۾ ٽائيپ ڪرڻ شروع ڪريو (وڌيڪ ڄاڻڻ لاءِ [$1 امدادي صفحو] ڏسندا). جي توهان هتي غلطيءَ ۾ اچي ويا آهيو تہ رڳو پنهنجي جهانگُوءَ جو '''back''' بٽڻ ڪلڪ ڪندا.",
+       "newarticletext": "توهان اهڙي صفحي جو ڳنڍڻو وٺي هتي پهتا آهيو، جيڪو اڃا وجود نٿو رکي.\nاهڙو صفحو جوڙڻ لاءِ، هيٺين باڪس ۾ ٽائيپ ڪرڻ شروع ڪريو (وڌيڪ ڄاڻڻ لاءِ [$1 امدادي صفحو] ڏسندا).\nجي توهان هتي غلطيءَ ۾ اچي ويا آهيو، تہ رڳو پنهنجي جهانگُوءَ جو <strong>back</strong> تي ٽڙڪ ڪريو.",
        "noarticletext": "في‌الوقت هن صفحي اندر ڪو بہ ٽيڪسٽ نہ آهي.\nتوهان ٻين صفحن ۾ [[Special:Search/{{PAGENAME}}|search ساڳي عنوان جي ڳولا]] ڪري سگھو ٿا،  \n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} لاڳاپيل لاگس ۾ ڳوليو]،\nor [{{fullurl:{{FULLPAGENAME}}|action=edit}} هيءُ صفحو ترميميو]</span>.",
        "userpage-userdoesnotexist-view": "يُوزر کاتو $1 درج ٿيل نہ آهي.",
        "blocked-notice-logextract": "هيءَ يُوزر في‌الحال بندشيل آهي. تازو بندش لاگ حوالي طور پيش ڪجي ٿو:",
        "updated": "(تجديديل)",
        "note": "<strong>نوٽ:</strong>",
-       "previewnote": "<strong>'''هيءَ محظ پيش نگاهہ آهي.</strong> ترميمون اڃا سانڍجوين ناهن!'''",
+       "previewnote": "<strong>هيءَ فقط پيش نگاھ آهي.</strong>\nتوھان جون ترميمون اڃان نہ سانڍيون ويون آھن!",
        "continue-editing": "ترميم گاھ ڏانهن وڃو",
-       "editing": "زير ترميم $1",
+       "editing": "$1 سنواريندي",
        "creating": "$1 سرجيندي",
        "editingsection": "زير ترميم $1 (سيڪشن)",
        "editingcomment": "ترميم هيٺ $1 (نئون سيڪشن)",
        "protectedpagewarning": "<strong>چتاءُ: هيءَ صفحو اهڙيءَ ريت تحفظيو ويو آهي جو فقط منتظمين ئي ان کي سنواري سگھن ٿا. </strong>\nتازه ترين لاگ حوالي طور پيش ڪجي ٿو:",
        "semiprotectedpagewarning": "<strong>نوٽ: هيءَ صفحو اهڙيءَ ريت تحفظيو ويو آهي جو فقط کاتيدار يُوزرس ئي ان کي سنواري سگھن ٿا. </strong>\nتازه ترين لاگ حوالي طور پيش ڪجي ٿو:",
        "templatesused": "هن صفحي تي استعمال ٿيندڙ {{PLURAL:$1|سانچو|سانچا}}:",
-       "templatesusedpreview": "هن پيش نگاهہ ۾ استعمال ٿيل {{PLURAL:$1|سانچو|سانچا}}:",
+       "templatesusedpreview": "هن پيش نگاھ ۾ استعمال ٿيل {{PLURAL:$1|سانچو|سانچا}}:",
        "templatesusedsection": "هن سيڪشن ۾ استعمال ٿيل {{PLURAL:$1|سانچو|سانچا}}:",
        "template-protected": "(تحفظيل)",
        "template-semiprotected": "(نيم تحفظيل)",
        "history-show-deleted": "رڳو ڊاٺل",
        "histfirst": "اوائلي ترين",
        "histlast": "تازه ترين",
-       "historysize": "({{PLURAL:$1|1 ٻاٽڻ|$1 ٻاٽڻيون}})",
+       "historysize": "({{PLURAL:$1|1 بائيٽ|$1 بائيٽس}})",
        "historyempty": "(خالي)",
        "history-feed-title": "ترميمي سوانح",
        "history-feed-description": "وڪي جي هن صفحي جي ترميمي سوانح",
        "searchprofile-everything-tooltip": "سموري مواد ۾ ڳوليو",
        "searchprofile-advanced-tooltip": "مرضيءَ جي نانءُپولارن ۾ ڳوليو",
        "search-result-size": "$1 ({{PLURAL:$2|لفظُ|$2 لفظَ}})",
-       "search-redirect": "($1 کي چوريو)",
+       "search-redirect": "($1 کان چوريو)",
        "search-section": "(سيڪشن $1)",
        "search-category": "(ذمرو $1)",
        "search-suggest": "ڇا توهان جو مطلب $1 آهي؟",
        "preferences": "ترجيحات",
        "mypreferences": "ترجيحات",
        "prefs-edits": "ترميمن جو تعداد:",
-       "prefsnologintext2": "پنهنجون ترجيحات بدلائڻ لاءِ لاگ اِن ٿيو.",
+       "prefsnologintext2": "پنهنجون ترجيحات بدلائڻ لاءِ داخل ٿيو.",
        "prefs-skin": "چَمَ",
        "skin-preview": "پيش نگاهہ",
        "datedefault": "بلا ترجيحا",
        "prefs-user-pages": "يُوزر صفحو",
        "prefs-personal": "يُوزر جو خدوخال",
        "prefs-rc": "تازيون تبديليون",
-       "prefs-watchlist": "Ù½Ù\8aÙ½ Ù\81Ù\87رست",
-       "prefs-editwatchlist": "Ù½Ù\8aÙ½ Ù\81Ù\87رست کي سنواريو",
-       "prefs-editwatchlist-label": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست ۾ درج ٿيل شين کي سنواريو:",
-       "prefs-editwatchlist-edit": "پنهنجي ٽيٽ فهرست ۾ موجود عنوان ڏسو ۽ مٽايو",
-       "prefs-editwatchlist-raw": "ÚªÚ\86Ù\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست سنواريو",
-       "prefs-editwatchlist-clear": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست ڊاهيو",
-       "prefs-watchlist-days": "Ù½Ù\8aÙ½ Ù\81Ù\87رست Û¾ Ú\8fÙ\8aکارڻ Ù\84اءÙ\90 Ú\8fÙ\8aÙ\86Ù\87Ù\86 :",
+       "prefs-watchlist": "Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست",
+       "prefs-editwatchlist": "Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست کي سنواريو",
+       "prefs-editwatchlist-label": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست ۾ درج ٿيل شين کي سنواريو:",
+       "prefs-editwatchlist-edit": "پنھنجي نظرھيٺ فھرست ۾ موجود عنوان ڏسو ۽ مٽايو",
+       "prefs-editwatchlist-raw": "ÚªÚ\86Ù\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست سنواريو",
+       "prefs-editwatchlist-clear": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست ڊاهيو",
+       "prefs-watchlist-days": "Ù\86ظرھÙ\8aÙº Ù\81ھرست Û¾ Ú\8fÙ\8aکارڻ Ù\84اءÙ\90 Ú\8fÙ\8aÙ\86Ù\87Ù\86:",
        "prefs-watchlist-days-max": "وڌ ۾ وڌ $1 {{PLURAL:$1|ڏينهن}}",
        "prefs-watchlist-edits-max": "وڌ ۾ وڌ تعداد: 1000",
-       "prefs-watchlist-token": "Ù½Ù\8aÙ½ Ù\84سٽ جو ٽوڪن:",
+       "prefs-watchlist-token": "Ù\86ظرھÙ\8aÙº Ù\81ھرست جو ٽوڪن:",
        "prefs-misc": "متفرق",
-       "prefs-resetpass": "ڳجھو لفظ بدلايو",
+       "prefs-resetpass": "ڳجھولفظ بدلايو",
        "prefs-changeemail": "برق ٽپال پتو مِٽايو يا بدلايو",
        "prefs-setemail": "ڪو برق ٽپال پتو ڄاڻايو",
        "prefs-email": "برق ٽپال چارا",
        "prefs-dateformat": "تاريخ جو طرز",
        "prefs-advancedediting": "عمومي چارا",
        "prefs-editor": "ايڊيٽر",
-       "prefs-preview": "پيش نگاهہ",
+       "prefs-preview": "پيش نگاھ",
        "prefs-advancedrc": "متقدم چارا",
        "prefs-advancedrendering": "متقدم چارا",
        "prefs-advancedsearchoptions": "متقدم چارا",
        "prefs-displaywatchlist": "نماڪار چارا",
        "prefs-tokenwatchlist": "ٽوڪن",
        "prefs-diffs": "تفاوت",
-       "prefs-help-prefershttps": "هيءَ ترجيح توهان جي ايندڙ لاگ اِن تي عمل ۾ ايندي.",
+       "prefs-help-prefershttps": "هيءَ ترجيح توهان جي ايند داخل ٿيڻ تي عمل ۾ ايندي.",
        "userrights": "يُوزر حقن جو بندوبست",
        "userrights-lookup-user": "يوزر گروپَ سنڀاليو",
        "userrights-user-editname": "يُوزرنانءُ ڄاڻايو:",
        "right-undelete": "ڪو صفحو اڻڊاهيو",
        "right-unblockself": "ڪنهن تان بندش ختم ڪريو",
        "right-editinterface": "يُوزر باهمرُو کي سنواريو",
-       "right-viewmywatchlist": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù½Ù\8aÙ½ Ù\84سٽ ڏسو",
+       "right-viewmywatchlist": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù\86ظرھÙ\8aÙº Ù\81ھرست ڏسو",
        "right-editmyoptions": "پنهنجون ترجيحات سنواريو",
        "right-import": "ٻين وڪيز کان صفحا درآمديو",
        "right-importupload": "ڪو فائيل چاڙهي صفحا درآمديو",
        "right-override-export-depth": "5ئين اونهائيءَ تائين ڳنڍيل صفحن سميت صفحا برآمديو",
        "right-sendemail": "ٻين يوزرس ڏانهن ايميل موڪليو",
        "right-passwordreset": "ڳجھو لفظ مقرري برق ٽپالون ڏسو",
-       "right-managechangetags": "اعدادخاني ۾ [[Special:Tags|ٽيگس]] سرجيو ۽ ڊاهيو.",
+       "right-managechangetags": "[[Special:Tags|ٽيگس]] سرجيو ۽ ڊاهيو.",
        "grant-group-email": "برق ٽپال اماڻيو",
        "grant-blockusers": "يُوزرس کي بندشيو ۽ اڻبندشيو",
        "grant-createaccount": "نئون کاتو کوليو",
-       "grant-editmywatchlist": "پنهنجي ٽيٽ فهرست سنواريو",
+       "grant-editmywatchlist": "پنھنجي نظرھيٺ فھرست سنواريو",
        "grant-editprotected": "تحفظيل صفحا سنواريو",
        "grant-rollback": "صفحن ۾ ڪيل تبديليون واپس ورايو",
        "grant-sendemail": "ٻين يوزرس ڏانهن ايميل موڪليو",
        "grant-uploadfile": "نئون فائيل چاڙهيو",
        "grant-basic": "بنيادي حقَ",
        "grant-viewdeleted": "ڊَٺَلَ فائيلَ ۽ صفحا ڏسو",
-       "grant-viewmywatchlist": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست ڏسو",
+       "grant-viewmywatchlist": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست ڏسو",
        "newuserlogpage": "يوزر کاتن جو لاگ",
        "rightslog": "يُوزر حق لاگ",
        "action-read": "هي صفحو پڙهو",
        "action-rollback": "ڪنهن مخصوص صفحي تي آخري ترميم ڪندڙ يُوزر جي سمورين ترميمن کي ترت واپس ورايو",
        "action-import": "ٻي ڪنهن وڪي کان صفحا درآمد ڪريو",
        "action-importupload": "ڪو فائيل چاڙهي صفحا درآمديو",
-       "action-unwatchedpages": "اڻ ٽيٽيل صفحن جي فهرست ڏسو",
+       "action-unwatchedpages": "اڻ ڏٺل صفحن جي فھرست ڏسو",
        "action-mergehistory": "هن صفحي جي سوانح ضم ڪريو",
        "action-userrights": "سڀ يوزر حق ترميم ڪريو",
        "action-userrights-interwiki": "ٻين وڪيز جي يوزرس جا حق ترميم ڪريو",
        "action-siteadmin": "اعدادخاني کي بند ڪريو يا کوليو",
        "action-sendemail": "برق ٽپال اماڻيو",
-       "action-editmywatchlist": "پنهنجي ٽيٽ فهرست سنواريو",
-       "action-viewmywatchlist": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست ڏسو",
+       "action-editmywatchlist": "پنھنجي نظرھيٺ فھرست سنواريو",
+       "action-viewmywatchlist": "Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست ڏسو",
        "action-viewmyprivateinfo": "پنهنجي ذاتي معلومات ڏسو",
        "action-editmyprivateinfo": "پنهنجي ذاتي معلومات سنواريو",
        "nchanges": "$1 {{PLURAL:$1|تبديلي|تبديليون}}",
        "recentchanges-legend": "تازين تبديلين جو آپشن",
        "recentchanges-summary": "هن صفحي تي وڪيءَ ۾ ڪيل تازيون ترين ترميمون ڏيکاريو.",
        "recentchanges-feed-description": "ۡهن روان رسد ۾ آيل تازيون تبديليون لهو",
-       "recentchanges-label-newpage": "هن ترميم سان نئون صفحو جڙيو.",
-       "recentchanges-label-minor": "هيءُ هڪ معمولي ترميم آهي.",
+       "recentchanges-label-newpage": "هن ترميم سان نئون صفحو جڙيو",
+       "recentchanges-label-minor": "هيء هڪ معمولي ترميم آهي",
        "recentchanges-label-bot": "هيءُ ترميم بوٽ عمل ۾ آندي.",
-       "recentchanges-label-plusminus": "هن صفحي جي ماپ ۾ هيترين ٻاٺڻين جو ڦير آيو آهي",
-       "recentchanges-legend-heading": "<strong>\"ڪنجي.</strong>",
+       "recentchanges-label-unpatrolled": "ھن ترميم جو اڃان گشت نہ ڪيو ويو آھي",
+       "recentchanges-label-plusminus": "هن صفحي جي ماپ ۾ هيترين بائيٽس جو ڦير آيو آهي",
+       "recentchanges-legend-heading": "<strong>ڪنجي:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (پڻ ڏسو [[Special:NewPages|نون صفحن جي فهرست]])",
        "recentchanges-submit": "ڏيکاريو",
        "rcnotefrom": "هيٺ {{PLURAL:$5|تبديلي آهي|تبديليون آهن}} کان <strong>$3, $4</strong> (تائين <strong>$1</strong> ) ڏيکاريل آهن.",
        "rclistfrom": "$3 $2 کان شروع ٿيندڙ نيون تبديليون",
        "rcshowhideminor": "$1 معمولي ترميمون",
-       "rcshowhideminor-show": "نمايو",
+       "rcshowhideminor-show": "ڏيکاريو",
        "rcshowhideminor-hide": "لڪايو",
        "rcshowhidebots": "$1 بوٽس",
-       "rcshowhidebots-show": "نمايو",
+       "rcshowhidebots-show": "ڏيکاريو",
        "rcshowhidebots-hide": "لڪايو",
        "rcshowhideliu": "$1 کاتيدار يوزرس",
        "rcshowhideliu-show": "ڏيکاريو",
        "rcshowhideliu-hide": "لڪايو",
        "rcshowhideanons": "$1 نامعلوم يُوزرس",
-       "rcshowhideanons-show": "نمايو",
+       "rcshowhideanons-show": "ڏيکاريو",
        "rcshowhideanons-hide": "لڪايو",
        "rcshowhidepatr": "$1 تاڻيل ترميمون",
        "rcshowhidepatr-show": "ڏيکاريو",
        "rcshowhidepatr-hide": "لڪايو",
-       "rcshowhidemine": "منهنجون ترميمون $1",
-       "rcshowhidemine-show": "نمايو",
+       "rcshowhidemine": "منھنجون ترميمون $1",
+       "rcshowhidemine-show": "ڏيکاريو",
        "rcshowhidemine-hide": "لڪايو",
        "rcshowhidecategorization": "$1 صفحاتي زمراڪاري",
        "rcshowhidecategorization-show": "ڏيکاريو",
        "recentchangeslinked-to": "رڳو ڄاڻايل صفحي سان ڳانڍيل صفحن ۾ ٿيل تبديليون نمايو",
        "upload": "فائيل چاڙهيو",
        "uploadbtn": "فائيل چاڙهيو",
-       "uploadnologin": "لاگ اِن ٿيل نہ آهيو",
+       "uploadnologin": "داخل ٿيل ناھيو",
        "uploadnologintext": "فائيل چاڙهڻ لاءِ $1.",
-       "uploaderror": "چاڙهہ چُڪَ",
-       "uploadlogpage": "چاڙهہ لاگ",
+       "uploaderror": "چاڙھ چُڪَ",
+       "uploadlogpage": "چاڙھ لاگ",
        "filename": "فائيل نانءُ",
        "filedesc": "خلاصو",
        "fileuploadsummary": "خلاصو:",
        "filedelete-maintenance-title": "فائيل ڊهي نہ سگھيو",
        "mimesearch": "مائيم ڳولا",
        "download": "اتاريو",
-       "unwatchedpages": "اڻ ٽيٽيل صفحا",
+       "unwatchedpages": "اڻ ڏٺل صفحا",
        "listredirects": "چورڻن جي فهرست",
        "unusedtemplates": "اڻ استعماليل سانچا",
        "unusedtemplateswlh": "ٻيا ڳنڍڻا",
        "withoutinterwiki": "ڪنهن بہ ٻي ٻوليءَ سان نہ ڳنڍيل صفحا",
        "withoutinterwiki-summary": "هيٺيان صفحا ڪنهن بہ ٻي ٻوليءَ ۾ ساڳي صفحي سان ڳنڍيل نہ آهن.",
        "withoutinterwiki-legend": "اڳياڙي",
-       "withoutinterwiki-submit": "نمايو",
+       "withoutinterwiki-submit": "ڏيکاريو",
        "fewestrevisions": "گھٽانگھٽ ترميميل صفحا",
-       "nbytes": "$1 {{PLURAL:$1|ٻاٽڻ|ٻاٽڻيون}}",
+       "nbytes": "$1 {{PLURAL:$1|بائيٽ|بائيٽس}}",
        "ncategories": "$1 {{PLURAL:$1|زمرو|زمرا}}",
        "ninterwikis": "$1 {{PLURAL:$1|بين‌الوڪي}}",
        "nlinks": "$1 {{PLURAL:$1|ڳنڍڻو|ڳنڍڻا}}",
        "sp-deletedcontributions-contribs": "ڀاڱيداريون",
        "linksearch-ns": "نانءُپولار",
        "linksearch-ok": "ڳوليو",
-       "listusers-submit": "نمايو",
+       "listusers-submit": "ڏيکاريو",
        "listusers-noresult": "ڪو بہ يُوزر نہ لڌو",
        "listusers-blocked": "(بندشيل)",
        "activeusers": "سرگرم يُوزرس جي فهرست",
        "emailccme": "نياپي جو پرت مون کي برق ٽپال ڪريو.",
        "emailsent": "برق ٽپال اماڻجي چڪي",
        "emailsenttext": "توهان جو برق ٽپال نياپو اماڻجي چڪو آهي.",
-       "watchlist": "Ù½Ù\8aÙ½ Ù\81Ù\87رست",
-       "mywatchlist": "Ù½Ù\8aÙ½ Ù\81Ù\87رست",
-       "addwatch": "Ù½Ù\8aÙ½ Ù\81Ù\87رست ۾ شامل ڪريو",
-       "addedwatchtext": "صÙ\81Ø­Ù\88\"[[:$1]]\" Ø§Ù\86 Ø¬Ù\8a Ø¨Ø­Ø« Ù\88ارÙ\88 ØµÙ\81Ø­Ù\88 Ø§Ù\88Ù\87اÙ\86 Ø¬Ù\8a [[Special:Watchlist|Ù½Ù\8aÙ½ Ù\81Ù\87رست]] ۾ شامل ڪيو ويو آهي.",
-       "removewatch": "Ù½Ù\8aÙ½ Ù\81Ù\87رست Ù\85اÙ\86 Ø®Ø§Ø±Ø¬ ÚªØ±يو",
-       "removedwatchtext": "صÙ\81Ø­Ù\88 Ø¨Ø¹Ù\86Ù\88اÙ\86 \"[[:$1]]\" ØªÙ\88Ù\87اÙ\86 Ø¬Ù\8a [[Special:Watchlist|Ù½Ù\8aÙ½ Ù\81Ù\87رست]] مان هٽي چڪو آهي.",
-       "removedwatchtext-short": "\"صÙ\81Ø­Ù\88 Ø¨Ø¹Ù\86Ù\88اÙ\86 \"$1\" ØªÙ\88Ù\87اÙ\86 Ø¬Ù\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست مان هٽي چڪو آهي.\"",
-       "watch": "Ù½Ù\8aÙ½Ù\8aو",
-       "watchthispage": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù½Ù\8aÙ½Ù\8aو",
-       "unwatch": "اڻ ٽيٽيو",
-       "unwatchthispage": "Ù½Ù\8aÙ½ڻ ڇڏيو",
+       "watchlist": "Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست",
+       "mywatchlist": "Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست",
+       "addwatch": "Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست ۾ شامل ڪريو",
+       "addedwatchtext": "صÙ\81Ø­Ù\88\"[[:$1]]\" Ø§Ù\86 Ø¬Ù\8a Ø¨Ø­Ø« Ù\88ارÙ\88 ØµÙ\81Ø­Ù\88 Ø§Ù\88Ù\87اÙ\86 Ø¬Ù\8a [[Special:Watchlist|Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست]] ۾ شامل ڪيو ويو آهي.",
+       "removewatch": "Ù\86ظرھÙ\8aÙº Ù\81ھرست Ù\85اÙ\86 Ú¾Ù½Ø§يو",
+       "removedwatchtext": "صÙ\81Ø­Ù\88 Ø¨Ø¹Ù\86Ù\88اÙ\86 \"[[:$1]]\" ØªÙ\88Ù\87اÙ\86 Ø¬Ù\8a [[Special:Watchlist|Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست]] مان هٽي چڪو آهي.",
+       "removedwatchtext-short": "\"صÙ\81Ø­Ù\88 Ø¨Ø¹Ù\86Ù\88اÙ\86 \"$1\" ØªÙ\88Ù\87اÙ\86 Ø¬Ù\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست مان هٽي چڪو آهي.\"",
+       "watch": "Ù\86ظرھÙ\8aÙº Ø±Ú©و",
+       "watchthispage": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù\86ظرھÙ\8aÙº Ø±Ú©و",
+       "unwatch": "نظرھيٺ نہ رکو",
+       "unwatchthispage": "Ù\86ظرھÙ\8aÙº Ø±Ú©ڻ ڇڏيو",
        "notanarticle": "غير موادي صفحو",
        "watchlist-details": "{{PLURAL:$1|$1 صفحو|$1 صفحا}} توهان جي ٽيٽ فهرست، ڳالھ ٻولھ جا صفحا الڳ شمار نٿا ٿين.",
        "wlshowlast": "گذريل $1 ڪلاڪ $2 ڏينهن ڏيکاريو",
        "wlshowhideliu": "کاتيدار يُوزرس",
        "wlshowhideanons": "گمنام يُوزرس",
        "wlshowhidemine": "منهنجون ترميمون",
-       "watchlist-options": "زيرِ نظر فهرست جا چارا",
-       "watching": "Ù½Ù\8aÙ½Ù\8aندي...",
-       "unwatching": "اڻ ٽيٽيندي...",
+       "watchlist-options": "نظرھيٺ فھرست جا چارا",
+       "watching": "Ù\86ظرھÙ\8aÙº Ø±Ú©ندي...",
+       "unwatching": "نظرھيٺان ڪڍندي...",
        "enotif_reset": "سڀ گھميل صفحن تي نشان لڳايو",
        "enotif_impersonal_salutation": "{{SITENAME}} يُوزر",
        "enotif_lastdiff": "هي تبديلي ڏسڻ لاءِ $1 ڏسو",
        "protect-expiry-options": "1 ڪلاڪ:1 hour,1 ڏينهن:1 day,1 هفتو:1 week,2 هفتو:2 weeks,1 مهينا:1 month,3 مهينا:3 months,6 مهينا:6 months,1 سال:1 year,اڻ کٽ:infinite",
        "restriction-type": "اجازتنامو:",
        "restriction-level": "روڪ سطح:",
-       "pagesize": "(ٻاٽڻيون)",
+       "pagesize": "(بائيٽس)",
        "restriction-edit": "سنواريو",
        "restriction-move": "چوريو",
        "restriction-create": "سرجيو",
        "contribsub2": "{{GENDER:$3|$1}} ($2) لاءِ",
        "contributions-userdoesnotexist": "يُوزر کاتو \"$1\" درج ٿيل نہ آهي.",
        "uctop": "(هاڻوڪو)",
-       "month": "Ù\85Ù\87Ù\8aÙ\86Ù\88 (۽ اڳوڻيون):",
-       "year": "سال (۽ اڳوڻيون):",
+       "month": "Ù\85Ù\87Ù\8aÙ\86Ù\8a Ú©Ø§Ù\86 (۽ اڳوڻيون):",
+       "year": "سال کان (۽ اڳوڻيون):",
        "sp-contributions-newbies": "صرف نون کاتن جون ڀاڱيداريون ڏيکاريو",
        "sp-contributions-newbies-sub": "نون کاتن لاءِ",
        "sp-contributions-newbies-title": "نون کاتن جي لاءِ يوزر جون ڀاڱيداريون",
-       "sp-contributions-blocklog": "بÙ\86سش لاگ",
+       "sp-contributions-blocklog": "بÙ\86دش لاگ",
        "sp-contributions-deleted": "ڊاٿل {{GENDER:$1|يوزر}} ڀاڱيداريون",
        "sp-contributions-uploads": "چاڙھَ",
        "sp-contributions-logs": "لاگس",
-       "sp-contributions-talk": "ڳالھہ",
+       "sp-contributions-talk": "ڳالھ",
        "sp-contributions-userrights": "يُوزر حقن جي سنڀال",
        "sp-contributions-search": "ڀاڱيدارين لاءِ ڳولا ڪريو",
        "sp-contributions-username": "آءِپي پتو يا يوزرنانءُ:",
        "unlockbtn": "اعدادخاني کي کوليو",
        "move-page": "$1 چوريو",
        "move-page-legend": "صفحو چوريو",
-       "movepagetext": "هيٺيون فارم استعمال ڪندي ڪنهن صفحي کي نئون عنوان ڏئي سگھجي ٿو، جنهن سان سمورو صفحو نئين عنوان ڏانهن هليو ويندو. \nاڳوڻو عنوان نئين عنوان ڏانهن چورڻو بنجي ويندو. \nتوهان  چورڻن کي سنواري سگھو ٿا جيڪي اصل عنوان ڏانهن خودبخود اشارو ڪن ٿا.\nIf you choose not to, be sure to check for [[Special:DoubleRedirects|double]] or [[Special:BrokenRedirects|broken redirects]].\nان ڳالهه جي پڪ ڪرڻ ذميواري توهان تي آهي ته ڳنڍڻا اتي ئي وٺي وڃن ٿا جتي انهن کي وٺي وڃڻ گھرجي.\n\nياد رکندا ته جيڪڏهن نئين عنوان سان اڳي ئي ڪو مضمون موجود آهي ته پوءِ صفحو '''نه''' چوريو ويندو، سوا ان جي ته موجوده صفحو محظ خالي آهي يا ڪا به سوانح نه رکندڙ ڪو چورڻو آهي.\n\n<strong>خبردار!</strong>\nاها هڪ مقبول صفحي لاءِ ڪا غير متوقه ۽ انتهائي اڻوڻندڙ تبديلي ثابت ٿي سگھي ٿي؛ براءِ مهرباني اڳتي وڌڻ کان اڳ پڪ ڪندا ته توهان اها تبديلي آڻڻ جي نتيجن کان چڱيءَ ريت واقف آهيو.",
+       "movepagetext": "هيٺيون فارم استعمال ڪندي ڪنهن صفحي کي نئون عنوان ڏئي سگھجي ٿو، جنهن سان سمورو صفحو نئين عنوان ڏانهن هليو ويندو. \nاڳوڻو عنوان نئين عنوان ڏانهن چورڻو بنجي ويندو. \nتوهان  چورڻن کي سنواري سگھو ٿا جيڪي اصل عنوان ڏانهن خودبخود اشارو ڪن ٿا.\nIf you choose not to, be sure to check for [[Special:DoubleRedirects|double]] or [[Special:BrokenRedirects|broken redirects]].\nان ڳالهه جي پڪ ڪرڻ ذميواري توهان تي آهي ته ڳنڍڻا اتي ئي وٺي وڃن ٿا جتي انهن کي وٺي وڃڻ گھرجي.\n\nياد رکندا ته جيڪڏهن نئين عنوان سان اڳي ئي ڪو مضمون موجود آهي ته پوءِ صفحو '''نه''' چوريو ويندو، سوا ان جي ته موجوده صفحو محظ خالي آهي يا ڪا به سوانح نه رکندڙ ڪو چورڻو آهي.\n\n<strong>نوٽ!</strong>\nاها هڪ مقبول صفحي لاءِ ڪا غير متوقه ۽ انتهائي اڻوڻندڙ تبديلي ثابت ٿي سگھي ٿي؛ براءِ مهرباني اڳتي وڌڻ کان اڳ پڪ ڪندا ته توهان اها تبديلي آڻڻ جي نتيجن کان چڱيءَ ريت واقف آهيو.",
        "movepagetalktext": "جيڪڏهن توهان هن خاني کي نشان لڳائيندئو، واسطيدار مباحثي صفحو پاڻ ئي چوريو ويندو ماسواءِ اتي ڪو اڳ ئي ڪو غيرخالي مباحثي صفحو موجود هجي.\n\nان صورت ۾، جيڪڏهن توهان چاهيو ته صفحي کي پاڻ چوري يا ضم ڪري سگھو ٿا.",
        "movenotallowed": "توهان کي صفحا چورڻ جي اجازت حاصل ڪانهي.",
        "movenotallowedfile": "توهان کي فائيلس چورڻ جي اجازت حاصل ڪانهي.",
        "tooltip-pt-userpage": "{{GENDER:|توھانجو يوزر}} صفحو",
        "tooltip-pt-mytalk": "{{GENDER:|توھانجو}} يوزر صفحو",
        "tooltip-pt-preferences": "{{GENDER:|توھانجون}} ترجيحات",
-       "tooltip-pt-watchlist": "توهان جي ٽيٽ فهرست ۾ شامل صفحا",
+       "tooltip-pt-watchlist": "توھان جي تبديلين جي نظرھيٺ صفحن جي فھرست",
        "tooltip-pt-mycontris": "{{GENDER:|توھانجي}} ڀاڱيدارين جي فھرست",
-       "tooltip-pt-login": "توهان کي همٿائجي ٿو تہ توهان لاگ اِن ٿيو، بهرحال اهو لازمي نہ آهي.",
-       "tooltip-pt-logout": "Ù\84اگ Ø¢Ø¦Ù\88Ù½",
-       "tooltip-pt-createaccount": "کاتو کولڻ ۽ لاگ اِن ٿيڻ تي توهان کي همٿايو ويندو؛  جيتوڻيڪ، اهو ضروري نہ آهي",
+       "tooltip-pt-login": "توھان کي ھمٿائجي ٿو تہ توهان داخل ٿيو؛ بھرحال، اھو لازمي ناھي",
+       "tooltip-pt-logout": "ٻاھر Ù\86ڪرÙ\88",
+       "tooltip-pt-createaccount": "کاتو کولڻ ۽ داخل ٿيڻ تي توھان کي ھمٿايو وڃي ٿو؛  جيتوڻيڪ، اهو ضروري ناھي",
        "tooltip-ca-talk": "موادي صفحي تي بحث",
        "tooltip-ca-edit": "هيءُ صفحو سنواريو",
        "tooltip-ca-addsection": "نئون سيڪشن شروع ڪريو",
        "tooltip-ca-protect": "هيءُ صفحو تحفظيو",
        "tooltip-ca-delete": "هيءُ صفحو ڊاهيو",
        "tooltip-ca-move": "هيءُ صفحو چوريو",
-       "tooltip-ca-watch": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست ۾ شامل ڪريو",
-       "tooltip-ca-unwatch": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست تان هٽايو",
+       "tooltip-ca-watch": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست ۾ شامل ڪريو",
+       "tooltip-ca-unwatch": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست تان هٽايو",
        "tooltip-search": "{{SITENAME}} ۾ ڳوليو",
        "tooltip-search-go": "تز ان ئي نالي سان ڪو صفحو موجود آهي تہ کوليو",
        "tooltip-search-fulltext": "هن متن لاءِ صفحا ڳوليو",
        "tooltip-p-logo": "مک صفحو گھمو",
        "tooltip-n-mainpage": "مک صفحو گھمو",
        "tooltip-n-mainpage-description": "مک صفحو گھمو",
-       "tooltip-n-portal": "هن رٿا بابت، توهان ڇا ٿا ڪري سگھو، ڪهڙي شَي ڪٿي ملندي",
-       "tooltip-n-currentevents": "تازن واقعن تي تفصيلي ڄاڻ لهو",
-       "tooltip-n-recentchanges": "هن وڪيءَ ۾ تازين تبديلين جي فهرست.",
-       "tooltip-n-randompage": "بلاترتيب ڪو بہ صفحو اتاريو",
-       "tooltip-n-help": "ڳولي لهڻ جي جاءِ",
-       "tooltip-t-whatlinkshere": "هتان ڳنڍيل سمورا وڪي صفحا",
+       "tooltip-n-portal": "ھن رٿا بابت، توھان ڇا ٿا ڪري سگھو، شيون ڪٿي ڳولھجن",
+       "tooltip-n-currentevents": "تازن واقعن تي تفصيلي ڄاڻ لھو",
+       "tooltip-n-recentchanges": "ھن وڪيءَ ۾ تازين تبديلين جي فھرست",
+       "tooltip-n-randompage": "ڪو بہ بلاترتيب صفحو اتاريو",
+       "tooltip-n-help": "ڳولي لھڻ جي جاءِ",
+       "tooltip-t-whatlinkshere": "ھتان ڳنڍيل سمورن وڪي صفحن جي فھرست",
        "tooltip-t-recentchangeslinked": "ويجھڙائيءَ ۾ صفحن ۾ ٿيل تبديليون هن صفحي سان ڳنڍيل آهن",
        "tooltip-feed-atom": "هن صفحي لاءِ ايٽم فيڊ",
        "tooltip-t-contributions": "{{GENDER:$1|ھن يوزر}} جي ڀاڱيدارين جي فھرست",
        "tooltip-t-permalink": "صفحي جي ان نظرثاليءَ ڏانهن مستقل ڳنڍڻو",
        "tooltip-ca-nstab-main": "مواد جي صفحي کي ڏسو",
        "tooltip-ca-nstab-user": "هن جو يُوزر صفحو ڏسو",
-       "tooltip-ca-nstab-special": "هيءُ خاص صفحو آهي، ان ۾ ترميم ڪري نہ ٿي سگھجي.",
+       "tooltip-ca-nstab-special": "هيءُ خاص صفحو آهي، ان ۾ ترميم ڪري نٿي سگھجي",
        "tooltip-ca-nstab-project": "رٿائي صفحو ڏسو",
        "tooltip-ca-nstab-image": "هن فائيل جو صفحو ڏسو",
        "tooltip-ca-nstab-template": "سانچو ڏسو",
        "tooltip-ca-nstab-category": "هن زمري جو صفحو ڏسو",
        "tooltip-minoredit": "ان کي هڪ معمولي ترميم ڄاڻايو",
        "tooltip-save": "پنهنجون ڪيل تبديليون سانڍيو",
-       "tooltip-preview": "سانڍڻ کان اڳ براءِ مهرباني پنهنجي تبديلين تي پيش نگاهه وجھندا!",
+       "tooltip-preview": "پنھنجي تبديلين تي نگاھ وجھو. براءِ مھرباني اھو سانڍڻ کان اڳ ڪندا.",
        "tooltip-diff": "پنهنجون ڪيل تبديليون ڏسو.",
        "tooltip-compareselectedversions": "هن صفحي جن ٻن چونڊيل پرتن درميان تفاوت ڏسو.",
-       "tooltip-watch": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست ۾ شامل ڪريو",
+       "tooltip-watch": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست ۾ شامل ڪريو",
        "tooltip-rollback": "\"واپس پرايو\" هن صفحي ۾ پوئين ڀاڱيدار جي ڪيل ترميم (ترميمن) کي هڪ ڪلڪ سان اڻڪري ٿو.",
        "tooltip-summary": "ننڍو خلاصو ڏيو",
        "anonymous": "گمنام {{PLURAL:$1|يوزر|يوزرس}} جو {{SITENAME}}",
        "file-nohires": "اڃا سنهو تحلل ميسر ناهي.",
        "svg-long-desc": "ايس وي جي فائيل، اٽڪل $1 × $2 عڪسلون، فائيل سائيز: $3",
        "show-big-image": "اصلوڪو فائيل",
-       "show-big-image-preview": "هن پيش نگاهہ جي ماپ: $1",
+       "show-big-image-preview": "هن پيش نگاھ جي ماپ: $1",
        "show-big-image-other": "ٻيا {{PLURAL:$2|تحلل}}:$1",
        "show-big-image-size": "$1*$2 پڪزلس",
        "newimages": "نون فائيلن جي گيلري",
        "confirmemail_subject": "{{SITENAME}} برق ٽپال پتي جي تصديق",
        "recreate": "ورسرجيو",
        "confirm-watch-button": "ٺيڪ",
-       "confirm-watch-top": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù½Ù\8aÙ½ Ù\81Ù\87رست ۾ شامل ڪندا؟",
+       "confirm-watch-top": "Ù\87Ù\8aØ¡Ù\8f ØµÙ\81Ø­Ù\88 Ù¾Ù\86Ù\87Ù\86جÙ\8a Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست ۾ شامل ڪندا؟",
        "confirm-unwatch-button": "ٺيڪ",
        "confirm-unwatch-top": "هيءُ صفحو پنهنجي ٽيٽ فهرست مان هٽائيندا؟",
        "quotation-marks": "\"$1\"",
        "table_pager_limit_label": "وَٿُون في صفحو:",
        "table_pager_limit_submit": "ھلو",
        "table_pager_empty": "ڪو بہ نتيجو نہ مليو",
-       "watchlistedit-normal-title": "Ù½Ù\8aÙ½ Ù\81Ù\87رست کي سنواريو",
+       "watchlistedit-normal-title": "Ù\86ظرھÙ\8aÙº Ù\81Ú¾رست کي سنواريو",
        "watchlistedit-raw-titles": "عنوانَ:",
        "watchlistedit-clear-titles": "عنوانَ:",
        "watchlisttools-view": "لاڳاپيل تبديليون ڏسو",
        "watchlisttools-edit": "ٽيٽ فهرست ڏسو ۽ سنواريو",
        "watchlisttools-raw": "ڪچي ٽيٽ فهرست سنواريو",
-       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|ڳالهہ]])",
+       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|ڳالھ]])",
        "version": "ڀيرو",
        "version-extensions": "تنصيب شده توسيعات",
        "version-skins": "تنصيب شده چَمڙيون",
        "feedback-subject": "موضوع:",
        "feedback-submit": "جمع ڪرايو",
        "feedback-thanks-title": "توهان جي مهرباني!",
-       "searchsuggest-search": "ڳوليو",
+       "searchsuggest-search": "ڳوليو {{SITENAME}}",
        "api-error-filename-tooshort": "فائيل‌نانءَُ هيڪاندو ننڍو آهي.",
        "api-error-unclassified": "ڪا اڻجاتل چُڪَ واقع ٿي.",
        "api-error-unknown-code": "اڻڄاتل چُڪَ: \"$1\".",
index 4dec610..8190add 100644 (file)
        "movelogpagetext": "Prikazujem seznam prestavljenih strani.",
        "movesubpage": "{{PLURAL:$1|Podstran|Podstrani}}",
        "movesubpagetext": "Ta stran ima $1 {{PLURAL:$1|podstran prikazano|podstrani prikazane}} spodaj.",
+       "movesubpagetalktext": "Pripadajoča stran ima $1 {{PLURAL:$1|podstran, prikazano|podstrani, prikazani|podstrani, prikazane|podstrani, prikazanih}} spodaj.",
        "movenosubpage": "Ta stran nima podstrani.",
        "movereason": "Razlog:",
        "revertmove": "vrni",
        "usercssispublic": "Pomnite: Podstrani CSS naj ne vsebujejo zaupnih podatkov, saj so vidne tudi drugim uporabnikom.",
        "restrictionsfield-badip": "Neveljaven IP-naslov ali obseg: $1",
        "restrictionsfield-label": "Dovoljeni IP-obsegi:",
-       "restrictionsfield-help": "En IP-naslov ali CIDR-območje na vrstico. Da omogočite vse, uporabite<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "En IP-naslov ali CIDR-območje na vrstico. Da omogočite vse, uporabite<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Napaka: $1",
+       "edit-error-long": "Napake:\n\n$1"
 }
index b6beebe..a43a770 100644 (file)
        "enotif_subject_created": "Страницу $1 на {{SITENAME}} {{GENDER:$2|направио је|направила је|направио је}} $2",
        "enotif_subject_moved": "Страницу $1 на {{SITENAME}} {{GENDER:$2|преместио је|преместила је}} $2",
        "enotif_subject_restored": "Страницу $1 на {{SITENAME}} {{GENDER:$2|вратио је|вратила је|вратио је}} $2",
-       "enotif_subject_changed": "Страницу $1 на {{SITENAME}} {{GENDER:$2|променио је|променила је|променио је}} $2",
+       "enotif_subject_changed": "Страницу $1 на {{SITENAME}} {{GENDER:$2|променио|променила}} је $2",
        "enotif_body_intro_deleted": "Страницу $1 на {{SITENAME}} {{GENDER:$2|обрисао|обрисала}} је $2 дана $PAGEEDITDATE Погледајте $3.",
        "enotif_body_intro_created": "Страницу $1 на {{SITENAME}} {{GENDER:$2|направио|направила}} је $2 дана $PAGEEDITDATE Тренутна измена налази се на $3.",
        "enotif_body_intro_moved": "Страницу $1 на {{SITENAME}} {{GENDER:$2|преместио|преместила}} је $2 дана $PAGEEDITDATE Тренутна измена налази се на  $3.",
index 76545f0..57bf080 100644 (file)
        "enotif_subject_created": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|napravio je|napravila je}} $2",
        "enotif_subject_moved": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|premestio je|premestila je}} $2",
        "enotif_subject_restored": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|vratio je|vratila je}} $2",
-       "enotif_subject_changed": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|promenio je|promenila je}} $2",
+       "enotif_subject_changed": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|promenio|promenila}} je $2",
        "enotif_body_intro_deleted": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|obrisao|obrisala}} je $2 dana $PAGEEDITDATE Pogledajte $3.",
        "enotif_body_intro_created": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|napravio|napravila}} je $2 dana $PAGEEDITDATE Trenutna izmena nalazi se na $3.",
        "enotif_body_intro_moved": "Stranicu $1 na {{SITENAME}} {{GENDER:$2|premestio|premestila}} je $2 dana $PAGEEDITDATE Trenutna izmena nalazi se na  $3.",
index b32f6ba..e7e4a26 100644 (file)
        "movelogpagetext": "Listan nedan visar sidor som flyttats.",
        "movesubpage": "{{PLURAL:$1|Undersida|Undersidor}}",
        "movesubpagetext": "Denna sida har $1 {{PLURAL:$1|undersida|undersidor}} som visas nedan.",
+       "movesubpagetalktext": "Den motsvarande diskussionssidan har $1 {{PLURAL:$1|undersida|undersidor}} som visas nedan.",
        "movenosubpage": "Denna sida har inga undersidor.",
        "movereason": "Anledning:",
        "revertmove": "återställ",
        "newimages-showbots": "Visa uppladdningar av botar",
        "newimages-hidepatrolled": "Dölj patrullerade uppladdningar",
        "noimages": "Ingenting att se.",
+       "gallery-slideshow-toggle": "Växla miniatyrer",
        "ilsubmit": "Sök",
        "bydate": "efter datum",
        "sp-newimages-showfrom": "Visa nya filer från och med kl. $2 den $1",
        "feedback-thanks": "Tack! Din feedback har skickats till sidan \"[$2 $1]\".",
        "feedback-thanks-title": "Tack!",
        "feedback-useragent": "Användaragent:",
-       "searchsuggest-search": "Sök",
+       "searchsuggest-search": "Sök på {{SITENAME}}",
        "searchsuggest-containing": "innehåller...",
        "api-error-autoblocked": "Din IP-adress har blockerats automatiskt eftersom den har använts av en blockerad användare.",
        "api-error-badaccess-groups": "Du får inte ladda upp filer till denna wiki.",
        "usercssispublic": "Observera: CSS-undersidor bör inte innehålla konfidentiella uppgifter eftersom de kan ses av andra användare.",
        "restrictionsfield-badip": "Ogiltig IP-adress eller intervall: $1",
        "restrictionsfield-label": "Tillåtna IP-intervall:",
-       "restrictionsfield-help": "En IP-adress eller CIDR-intervall per rad. För att aktivera allting, använd<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "En IP-adress eller CIDR-intervall per rad. För att aktivera allting, använd<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "Fel: $1",
+       "edit-error-long": "Fel:\n\n$1"
 }
index a414c9d..73a8101 100644 (file)
@@ -52,7 +52,7 @@
        "tog-enotifminoredits": "పేజీలు మరియు దస్త్రాలలో జరిగే చిన్న మార్పులకు కూడా నాకు ఈ-మెయిలును పంపు",
        "tog-enotifrevealaddr": "గమనింపు మెయిళ్ళలో నా ఈ-మెయిలు చిరునామాను చూపించు",
        "tog-shownumberswatching": "వీక్షకుల సంఖ్యను చూపు",
-       "tog-oldsig": "ప్రస్తుత సంతకం:",
+       "tog-oldsig": "à°®à±\80 à°ªà±\8dà°°à°¸à±\8dà°¤à±\81à°¤ à°¸à°\82à°¤à°\95à°\82:",
        "tog-fancysig": "సంతకాన్ని వికీపాఠ్యంగా తీసుకో (ఆటోమెటిక్‌ లింకు లేకుండా)",
        "tog-uselivepreview": "తాజా మునుజూపును వాడు",
        "tog-forceeditsummary": "దిద్దుబాటు సారాంశం ఖాళీగా ఉంటే ఆ విషయాన్ని నాకు సూచించు",
@@ -60,6 +60,7 @@
        "tog-watchlisthidebots": "బాట్లు చేసిన మార్పులను నా వీక్షణా జాబితాలో చూపించొద్దు",
        "tog-watchlisthideminor": "చిన్న మార్పులను నా వీక్షణా జాబితాలో చూపించొద్దు",
        "tog-watchlisthideliu": "లాగిన్ ఐన వాడుకరులు చేసే మార్పులను వీక్షణా జాబితాలో చూపించకు",
+       "tog-watchlistreloadautomatically": "ఫిల్టరు మారినప్పుడెల్లా వీక్షణ జాబితాను తిరిగి లోడు చెయ్యి (JavaScript అవసరం)",
        "tog-watchlisthideanons": "అజ్ఞాత వాడుకరుల మార్పులను వీక్షణా జాబితాలో చూపించకు",
        "tog-watchlisthidepatrolled": "నిఘా ఉన్న మార్పులను వీక్షణజాబితా నుంచి దాచిపెట్టు",
        "tog-watchlisthidecategorization": "పేజీ వర్గీకరణను దాచు",
        "newwindow": "(కొత్త కిటికీలో వస్తుంది)",
        "cancel": "రద్దుచేయి",
        "moredotdotdot": "ఇంకా...",
-       "morenotlisted": "à°\88 à°\9cాబితా à°¸à°\82à°ªà±\82à°°à±\8dà°£à°\82 à°\95ాదà±\81.",
+       "morenotlisted": "బహà±\81శా à°\88 à°\9cాబితా à°\85à°¸à°\82à°ªà±\82à°°à±\8dà°£à°\82.",
        "mypage": "పుట",
        "mytalk": "చర్చ",
        "anontalk": "చర్చ",
        "mypreferencesprotected": "మీ అభీష్టాలను సవరించేందుకు మీకు అనుమతి లేదు.",
        "ns-specialprotected": "ప్రత్యేక పేజీలపై దిద్దుబాట్లు చేయలేరు.",
        "titleprotected": "[[User:$1|$1]] ఈ శీర్షికని సృష్టించకుండా ఇది సంరక్షించబడింది.\nఅందుకు ఇచ్చిన కారణం: <em>$2</em>.",
-       "filereadonlyerror": "à°«à±\88à°²à±\81 à°\96à°\9cానా \"$2\" à°°à±\80à°¡à±\8d-à°\93à°¨à±\8dà°²à±\80 à°¸à±\8dథితిలà±\8b à°\89à°\82à°¡à°\9fà°\82 à°\9aà±\87à°¤ \"$1\" à°«à±\88à°²à±\81à°²à±\8b à°®à°¾à°°à±\8dà°ªà±\81à°²à±\81 à°\9aà±\86à°¯à±\8dయలà±\87à°\95à°ªà±\8bయాà°\82.\n\nదానిà°\95à°¿ à°¤à°¾à°³à°\82 à°µà±\87సిన à°\85ధిà°\95ారి ఇచ్చిన వివరణ ఇది: \"$3\".",
+       "filereadonlyerror": "à°«à±\88à°²à±\81 à°\96à°\9cానా \"$2\" à°°à±\80à°¡à±\8d-à°\93à°¨à±\8dà°²à±\80 à°¸à±\8dథితిలà±\8b à°\89à°\82à°¡à°\9fà°\82 à°\9aà±\87à°¤ \"$1\" à°«à±\88à°²à±\81à°²à±\8b à°®à°¾à°°à±\8dà°ªà±\81à°²à±\81 à°\9aà±\86à°¯à±\8dయలà±\87à°\95à°ªà±\8bయాà°\82.\n\nదానిà°\95à°¿ à°¤à°¾à°³à°\82 à°µà±\87సిన à°¸à°¿à°¸à±\8dà°\9fà°®à±\81 à°¨à°¿à°°à±\8dవాహà°\95à±\81à°¡à±\81 ఇచ్చిన వివరణ ఇది: \"$3\".",
        "invalidtitle-knownnamespace": "పేరుబరి \"$2\", పాఠ్యము \"$3\" తో కూడిన ఈ శీర్షిక చెల్లనిది",
        "invalidtitle-unknownnamespace": "అపరిచితమైన పేరుబరి సంఖ్య \"$1\", పాఠ్యము \"$2\" తో కూడిన ఈ శీర్షిక చెల్లనిది",
        "exception-nologin": "లాగినై లేరు",
        "createacct-yourpasswordagain-ph": "సంకేతపదాన్ని మళ్ళీ ఇవ్వండి",
        "userlogin-remembermypassword": "నన్ను లాగిన్ చేసే ఉంచు",
        "userlogin-signwithsecure": "సురక్షిత కనెక్షను వాడు",
+       "cannotlogin-title": "లాగిన్ చెయ్యలేకున్నాం",
        "cannotloginnow-title": "ఇప్పుడు లాగిన్ అవలేరు",
        "cannotloginnow-text": "$1 ను వాడుతూండగా లాగౌట్ అవలేరు.",
+       "cannotcreateaccount-title": "ఖాతాలను సృష్టించలేము",
+       "cannotcreateaccount-text": "ఈ వికీలో నేరుగా ఖాతాలను సృష్టించడం సశక్తం చెయ్యలేదు.",
        "yourdomainname": "మీ డోమైను",
        "password-change-forbidden": "ఈ వికీలో మీరు సంకేతపదాలను మార్చలేరు.",
        "externaldberror": "డేటాబేసు అధీకరణలో లోపం జరిగింది లేదా మీ బయటి ఖాతాను తాజాకరించడానికి మీకు అనుమతి లేదు.",
        "eauthentsent": "ఇచ్చిన ఈ-మెయిలు అడ్రసుకు ధృవీకరణ మెయిలు పంపించాం.\nఇకపై మేము ఆ ఖాతాకు మెయిలు పంపాలంటే, ముందుగా మీరు ఆ మెయిల్లో సూచించినట్లుగా చేసి, ఈ చిరునామా మీదేనని ధృవీకరించాలి.",
        "throttled-mailpassword": "గడచిన {{PLURAL:$1|ఒక గంటలో|$1 గంటల్లో}} సంకేతపదం మార్చినట్లుగా ఒక మెయిలు పంపించివున్నాం.\nదుశ్చర్యలను నివారించేందుకు గాను, {{PLURAL:$1|ఒక గంటకు|$1 గంటలకు}} ఒక్కసారి మాత్రమే సంకేతపదం మార్పు మెయిలు పంపిస్తాము.",
        "mailerror": "మెయిలు పంపించడంలో లోపం: $1",
-       "acct_creation_throttle_hit": "మీ ఐపీ చిరునామా వాడుతున్న ఈ వికీ సందర్శకులు గత ఒక్క రోజులో {{PLURAL:$1|1 ఖాతాని|$1 ఖాతాలను}} సృష్టించారు, ఈ కాల వ్యవధిలో అది గరిష్ఠ పరిమితి.\nఅందువల్ల, ఈ ఐపీని వాడుతున్న సందర్శకులు ప్రస్తుతానికి ఇంక ఖాతాలని సృష్టించలేరు.",
+       "acct_creation_throttle_hit": "మీ ఐపీ చిరునామా వాడుతున్న ఈ వికీ సందర్శకులు గత $2 లో {{PLURAL:$1|1 ఖాతాను|$1 ఖాతాలను}} సృష్టించారు. ఈ కాల వ్యవధిలో అది గరిష్ఠ పరిమితి.\nఫలితంగా, ఈ ఐపీని వాడుతున్న సందర్శకులు ప్రస్తుతానికి ఇక ఖాతాలని సృష్టించలేరు.",
        "emailauthenticated": "మీ ఈ-మెయిలు చిరునామా $2న $3కి ధృవీకరింపబడింది.",
        "emailnotauthenticated": "మీ ఈ-మెయిలు చిరునామాను ఇంకా ధృవీకరించలేదు. \nకింద పేర్కొన్న అంశాలకు సంబంధించి ఎటువంటి ఈ-మెయిలునూ పంపించము.",
        "noemailprefs": "ఈ అంశాలు పని చెయ్యడానికి మీ అభిరుచుల్లో ఈమెయిలు చిరునామా ఇవ్వండి.",
        "passwordreset-emailelement": "వాడుకరిపేరు: \n$1\n\nతాత్కాలిక సంకేతపదం: \n$2",
        "passwordreset-emailsentemail": "ఈ ఈమెయిలు చిరునామా మీ ఖాతాకు అనుసంధించి ఉంటే, సంకేతపదం మార్పు ఈమెయిలు పంపించబడుతుంది.",
        "passwordreset-emailsentusername": "ఈ వాడుకరిపేరుకు ఏదైనా ఈమెయిలు చిరునామా అనుసంధించి ఉంటే, సంకేతపదం మార్పు ఈమెయిలు పంపించబడుతుంది.",
-       "passwordreset-emailsent-capture2": "à°¸à°\82à°\95à±\87తపదà°\82 à°®à°¾à°°à±\8dà°ªà±\81 {{PLURAL:$1|à°\88à°®à±\86యిలà±\81à°¨à±\81|à°\88à°®à±\86యిళà±\8dళనà±\81}} à°ªà°\82పిà°\82à°\9aà°¾à°\82. {{PLURAL:$1|వాడà±\81à°\95à°°à°¿à°ªà±\87à°°à±\81, à°¸à°\82à°\95à±\87తపదానà±\8dని|వాడà±\81à°\95à°°à°¿à°ªà±\87à°°à±\8dà°²à±\81, à°¸à°\82à°\95à±\87తపదాల à°\9cాబితానà±\81}} à°\95à°¿à°\82à°¦ చూపించాం.",
-       "passwordreset-emailerror-capture2": "{{GENDER:$2|వాడà±\81à°\95à°°à°¿à°\95à°¿}} à°\88à°®à±\86యిలà±\81 à°ªà°\82పడà°\82 à°µà°¿à°«à°²à°®à±\88à°\82ది: $1 {{PLURAL:$3|వాడà±\81à°\95à°°à°¿à°ªà±\87à°°à±\81, à°¸à°\82à°\95à±\87తపదానà±\8dని|వాడà±\81à°\95à°°à°¿à°ªà±\87à°°à±\8dà°²à±\81, à°¸à°\82à°\95à±\87తపదాల à°\9cాబితానà±\81}} à°\95à°¿à°\82à°¦ చూపించాం.",
+       "passwordreset-emailsent-capture2": "à°¸à°\82à°\95à±\87తపదà°\82 à°®à°¾à°°à±\8dà°ªà±\81 {{PLURAL:$1|à°\88à°®à±\86యిలà±\81à°¨à±\81|à°\88à°®à±\86యిళà±\8dళనà±\81}} à°ªà°\82పిà°\82à°\9aà°¾à°\82. {{PLURAL:$1|వాడà±\81à°\95à°°à°¿à°ªà±\87à°°à±\81, à°¸à°\82à°\95à±\87తపదానà±\8dని|వాడà±\81à°\95à°°à°¿à°ªà±\87à°°à±\8dà°²à±\81, à°¸à°\82à°\95à±\87తపదాల à°\9cాబితానà±\81}} à°\87à°\95à±\8dà°\95à°¡ చూపించాం.",
+       "passwordreset-emailerror-capture2": "{{GENDER:$2|వాడà±\81à°\95à°°à°¿à°\95à°¿}} à°\88à°®à±\86యిలà±\81 à°ªà°\82పడà°\82 à°µà°¿à°«à°²à°®à±\88à°\82ది: $1 {{PLURAL:$3|వాడà±\81à°\95à°°à°¿à°ªà±\87à°°à±\81, à°¸à°\82à°\95à±\87తపదానà±\8dని|వాడà±\81à°\95à°°à°¿à°ªà±\87à°°à±\8dà°²à±\81, à°¸à°\82à°\95à±\87తపదాల à°\9cాబితానà±\81}} à°\87à°\95à±\8dà°\95à°¡ చూపించాం.",
        "passwordreset-invalideamil": "తప్పు ఈ-మెయిలు చిరునామా",
        "passwordreset-nodata": "వాడుకరిపేరుగానీ, ఈ-మెయిలు చిరునామా గానీ ఇవ్వలేదు",
        "changeemail": "ఈ-మెయిలు చిరునామా మార్పు లేదా తొలగింపు",
        "searchprofile-advanced-tooltip": "కస్టం నేంస్పేసులలో వెదుకు",
        "search-result-size": "$1 ({{PLURAL:$2|1 పదం|$2 పదాలు}})",
        "search-result-category-size": "{{PLURAL:$1|1 సభ్యుడు|$1 సభ్యులు}} ({{PLURAL:$2|1 ఉవవర్గం|$2 ఉపవర్గాలు}}, {{PLURAL:$3|1 దస్త్రం|$3 దస్త్రాలు}})",
-       "search-redirect": "(దారిమార్పు $1)",
+       "search-redirect": "($1 నుండి దారిమార్పు)",
        "search-section": "(విభాగం $1)",
        "search-category": "(వర్గం $1)",
        "search-file-match": "(ఫైలు విషయంతో సరిపోలుతోంది)",
        "search-suggest": "మీరు అంటున్నది ఇదా: $1",
+       "search-rewritten": "$1 కు ఫలితాలు చూపిస్తున్నాం. లేదంటే $2 కోసం వెతకండి.",
        "search-interwiki-caption": "సోదర ప్రాజెక్టులు",
        "search-interwiki-default": "$1 నుండి ఫలితాలు:",
        "search-interwiki-more": "(మరిన్ని)",
index c339149..b3fc2ca 100644 (file)
        "special-characters-group-khmer": "Khmer",
        "mw-widgets-dateinput-placeholder-day": "TTTT-BB-AA",
        "mw-widgets-dateinput-placeholder-month": "TTTT-BB",
-       "randomrootpage": "Alin mang pinag-ugatang/pinagmulang pahina"
+       "randomrootpage": "Alin mang pinag-ugatang/pinagmulang pahina",
+       "edit-error-long": "Mga kamalian:"
 }
index 0fe4217..2646d2c 100644 (file)
        "searchprofile-advanced-tooltip": "Шукати в заданих просторах назв",
        "search-result-size": "$1 ($2 {{PLURAL:$2|слово|слова|слів}})",
        "search-result-category-size": "{{PLURAL:$1|$1 елемент|$1 елементи|$1 елементів}} ({{PLURAL:$2|$2 підкатегорія|$2 підкатегорії|$2 підкатегорій}}, {{PLURAL:$3|$3 файл|$3 файли|$3 файлів}})",
-       "search-redirect": "(перенаправлення $1)",
+       "search-redirect": "(перенаправлення з $1)",
        "search-section": "(розділ $1)",
        "search-category": "(категорія $1)",
        "search-file-match": "(збігається із вмістом файлу)",
        "feedback-thanks": "Дякуємо! Ваші відгук розміщено на сторінці \"[$2 $1]\".",
        "feedback-thanks-title": "Дякуємо!",
        "feedback-useragent": "User Agent:",
-       "searchsuggest-search": "Пошук",
+       "searchsuggest-search": "Пошук у {{grammar:prepositional|{{SITENAME}}}}",
        "searchsuggest-containing": "що містять...",
        "api-error-autoblocked": "Вашу IP-адресу було заблоковано автоматично, тому що її використовував заблокований користувач.",
        "api-error-badaccess-groups": "Вам не дозволено завантажувати файли до цього вікіпроекту.",
index 73f4629..1c41e4a 100644 (file)
        "yourpasswordagain": "Kọ ọ̀rọ̀ìpamọ́ lẹ́ẹ̀kansí:",
        "createacct-yourpasswordagain": "Ẹ ṣe ìfidájú ọ̀rọ̀ìpamọ́",
        "createacct-yourpasswordagain-ph": "Ẹ kọ ọ̀rọ̀ìpamọ́ lẹ́ẹ̀kan síi",
-       "remembermypassword": "Ṣè'rántí ìwọlé mi lórí kọ̀mpútà yìí (fún ó pẹ́ jù {{PLURAL:$1|ọjọ́|ọjọ́}} $1)",
        "userlogin-remembermypassword": "Fi mí sí ìwọlé",
        "userlogin-signwithsecure": "Lo ìsopọ̀ ẹ̀rọ tó ní àbò",
        "yourdomainname": "Domain yín:",
        "movelogpagetext": "Nísàlẹ̀ ni àtòjọ gbogbo àwọn ìyípòdà ojúewé.",
        "movesubpage": "{{PLURAL:$1|Ojúewé abẹ́|Àwọn ojúewé abẹ́}}",
        "movesubpagetext": "Ojúewé yìí ní {{PLURAL:$1|ojúewé abẹ́|àwọn ojúewé abẹ́}} $1 tó hàn nísàlẹ̀.",
+       "movesubpagetalktext": "Ojúewé ọ̀rọ̀ rẹ̀ ní {{PLURAL:$1|ojúewé abẹ́|àwọn ojúewé abẹ́}} $1 tó hàn nísàlẹ̀.",
        "movenosubpage": "Ojúewé yìí kò ní àwọn abẹ́ojúewé.",
        "movereason": "Ìdíẹ̀:",
        "revertmove": "dápadà",
        "htmlform-submit": "Fúnsílẹ̀",
        "htmlform-reset": "Ìdápadà àwọn àtúnṣe",
        "htmlform-selectorother-other": "Òmíràn",
-       "sqlite-has-fts": "$1 pẹ̀lú àtìlẹ́yìn àwárí ìkọ̀rọ̀ kíkún",
-       "sqlite-no-fts": "$1 láìní àtìlẹ́yìn àwárí ìkọ̀rọ̀ kíkún",
        "logentry-delete-delete": "$1 pa ojúewé $3 rẹ́",
        "logentry-delete-restore": "$1 dá ojúewé $3 padà",
        "logentry-delete-event": "$1 ṣe àyípadà ìhànsí {{PLURAL:$5|ìṣẹ̀lẹ̀ àkọọ́lẹ̀ kan|àwọn ìṣẹ̀lẹ̀ àkọọ́lẹ̀ $5}} lórí $3: $4",
        "special-characters-group-gujarati": "Gujarati",
        "special-characters-group-thai": "Thai",
        "special-characters-group-lao": "Lao",
-       "special-characters-group-khmer": "Khmer"
+       "special-characters-group-khmer": "Khmer",
+       "edit-error-short": "Àṣìṣe: $1",
+       "edit-error-long": "Àwọn àsìṣe:\n\n\n$1"
 }
index 26e968e..f0b9726 100644 (file)
@@ -92,7 +92,8 @@
                        "Cosine02",
                        "Arthur2e5",
                        "Myy730",
-                       "SolidBlock"
+                       "SolidBlock",
+                       "D41D8CD98F"
                ]
        },
        "tog-underline": "链接下划线:",
        "namespaces": "命名空间",
        "variants": "变种",
        "navigation-heading": "导航菜单",
-       "errorpagetitle": "出错",
+       "errorpagetitle": "错误",
        "returnto": "返回至$1。",
        "tagline": "来自{{SITENAME}}",
        "help": "帮助",
        "nosuchactiontext": "URL指定的操作无效。您可能输入了错误的URL地址,或是点击了错误的链接。这也可能表明{{SITENAME}}使用的软件存在漏洞。",
        "nosuchspecialpage": "此特殊页面不存在",
        "nospecialpagetext": "<strong>您请求了一个无效的特殊页面。</strong>\n\n有效的特殊页面的列表可以在[[Special:SpecialPages|{{int:specialpages}}]]找到。",
-       "error": "出错",
+       "error": "错误",
        "databaseerror": "数据库错误",
        "databaseerror-text": "出现数据库查询错误。这可能表示软件中存在漏洞。",
        "databaseerror-textcl": "出现数据库查询错误。",
        "lockedbyandtime": "(由 {{GENDER:$1|$1}} 于$2 $3执行)",
        "move-page": "移动$1",
        "move-page-legend": "移动页面",
-       "movepagetext": "您可以使用下面的表单来重命名一个页面,同时将其版本历史移动到新页面。同时老的条目将会被重定向到新条目。您可以自动地将重定向更新到原条目。如果您不选择这样做的话,请检查[[Special:DoubleRedirects|双重]]或[[Special:BrokenRedirects|损坏重定向]]链接。您有责任确保链接会被正确指向他们应该被指向的地方。\n\n注意:即使新条目已经有对应页面,此页面也<strong>不会</strong>被移动,除非新页面无任何编辑历史或是重定向页。这意味着您可在误操作后将页面移回原处,同时,您也无法覆盖现有页面。\n\n<strong>注意:</strong>对这样一个经常被访问的页面而言这可能是一个重大且唐突的更改;请在行动前先了解您的修改可能带来的一切后果。",
+       "movepagetext": "您可以使用下面的表单来重命名一个页面,同时将其版本历史移动到新页面。同时老的条目将会被重定向到新条目。您可以自动地将指向老的条目的重定向更新为指向新条目。如果您不选择这样做的话,请检查[[Special:DoubleRedirects|双重]]或[[Special:BrokenRedirects|损坏重定向]]链接。您有责任确保链接会被正确指向他们应该被指向的地方。\n\n注意:如果新条目已经有对应页面,此页面将<strong>不会</strong>被移动,除非新页面是重定向页并且无任何修订历史。这意味着您可在误操作后将页面移回原处,同时,您无法覆盖现有页面。\n\n<strong>注意:</strong>对这样一个经常被访问的页面而言这可能是一个重大且唐突的更改;请在行动前先了解您的修改可能带来的一切后果。",
        "movepagetext-noredirectfixer": "用下面的表单来重命名一个页面,并将其版本历史同时移动到新页面。老的页面将成为新页面的重定向页。请检查[[Special:DoubleRedirects|双重重定向]]或[[Special:BrokenRedirects|损坏重定向]]链接。您应当负责确定所有链接依然会链到指定的页面。\n\n注意如果新页面已经有内容的话,页面将<strong>不会</strong>被移动,除非新页面无内容或是重定向页,而且没有版本历史。这意味着您再必要时可以在移动到新页面后再移回老的页面,同时您也无法覆盖现有页面。\n\n<strong>注意:</strong>对一个经常被访问的页面而言这可能是一个重大与唐突的更改;请在行动前先确定您了解其所可能带来的后果。",
        "movepagetalktext": "如果您勾选此框,相关联的讨论页将被自动移动到新的标题,除非这里已经有了一个非空讨论页。\n\n在这种情况下,如有需要,您将不得不手动移动或合并页面。",
        "moveuserpage-warning": "'''警告:'''你将移动一个用户页面。请注意,只有该页面会被移动,该用户''不''会被更名。",
        "movelogpagetext": "下面是所有页面移动的列表。",
        "movesubpage": "{{PLURAL:$1|子页面}}",
        "movesubpagetext": "该页面有$1个子页面在下面展示。",
+       "movesubpagetalktext": "相应讨论页有$1个{{PLURAL:$1|子页面}}在下面展示。",
        "movenosubpage": "这个页面没有子页面。",
        "movereason": "原因:",
        "revertmove": "恢复",
        "newimages-showbots": "显示机器人上传",
        "newimages-hidepatrolled": "隐藏已巡查的上传",
        "noimages": "无可查看文件。",
+       "gallery-slideshow-toggle": "开启/关闭缩略图",
        "ilsubmit": "搜索",
        "bydate": "按日期",
        "sp-newimages-showfrom": "从$1 $2开始显示新文件",
        "feedback-thanks": "谢谢!您的反馈已发布至页面“[$2 $1]”。",
        "feedback-thanks-title": "谢谢您!",
        "feedback-useragent": "用户代理:",
-       "searchsuggest-search": "搜索",
+       "searchsuggest-search": "搜索{{SITENAME}}",
        "searchsuggest-containing": "含有...",
        "api-error-autoblocked": "您的IP地址已被自动封禁,因为它曾被一位已封禁用户使用。",
        "api-error-badaccess-groups": "您没有将文件上传到此 wiki 的权限。",
        "usercssispublic": "请注意:CSS子页面不应包含机密数据,因为它们可以被其他用户查看。",
        "restrictionsfield-badip": "无效的IP地址或段:$1",
        "restrictionsfield-label": "允许的IP段:",
-       "restrictionsfield-help": "每行一个IP地址或CIDR段。要启用所有,可使用<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "每行一个IP地址或CIDR段。要启用所有,可使用<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "edit-error-short": "错误:$1",
+       "edit-error-long": "错误:\n\n$1"
 }
index 9740ef2..2262338 100644 (file)
@@ -63,7 +63,10 @@ class AddRFCAndPMIDInterwiki extends LoggedUpdateMaintenance {
                                [ 'iw_prefix' ],
                                [
                                        'iw_prefix' => 'rfc',
-                                       'iw_url' => 'https://tools.ietf.org/html/rfc$1'
+                                       'iw_url' => 'https://tools.ietf.org/html/rfc$1',
+                                       'iw_api' => '',
+                                       'iw_wikiid' => '',
+                                       'iw_local' => 0,
                                ],
                                __METHOD__
                        );
@@ -74,6 +77,9 @@ class AddRFCAndPMIDInterwiki extends LoggedUpdateMaintenance {
                        [
                                'iw_prefix' => 'pmid',
                                'iw_url' => 'https://www.ncbi.nlm.nih.gov/pubmed/$1?dopt=Abstract',
+                               'iw_api' => '',
+                               'iw_wikiid' => '',
+                               'iw_local' => 0,
                        ],
                        __METHOD__,
                        // If there's already a pmid interwiki link, don't
@@ -84,3 +90,6 @@ class AddRFCAndPMIDInterwiki extends LoggedUpdateMaintenance {
                return true;
        }
 }
+
+$maintClass = 'AddRFCAndPMIDInterwiki';
+require_once RUN_MAINTENANCE_IF_MAIN;
index 9ec61dc..3f0a83d 100644 (file)
@@ -34,11 +34,7 @@ class CheckComposerLockUpToDate extends Maintenance {
                $lock = new ComposerLock( $lockLocation );
                $json = new ComposerJson( $jsonLocation );
 
-               if ( $lock->getHash() === $json->getHash() ) {
-                       $this->output( "Your composer.lock file is up to date with current dependencies!\n" );
-                       return;
-               }
-               // Out of date, lets figure out which dependencies are old
+               // Check all the dependencies to see if any are old
                $found = false;
                $installed = $lock->getInstalledDependencies();
                foreach ( $json->getRequiredDependencies() as $name => $version ) {
@@ -61,8 +57,6 @@ class CheckComposerLockUpToDate extends Maintenance {
                                1
                        );
                } else {
-                       // The hash is the entire composer.json file,
-                       // so it can be updated without any of the dependencies changing
                        // We couldn't find any out-of-date dependencies, so assume everything is ok!
                        $this->output( "Your composer.lock file is up to date with current dependencies!\n" );
                }
index 97c8954..cdef7e0 100644 (file)
@@ -63,7 +63,8 @@ if ( $ext == 'php' || $ext == 'php5' ) {
        return true;
 }
 $mime = false;
-$lines = explode( "\n", file_get_contents( "includes/mime.types" ) );
+// Borrow mime type file from MimeAnalyzer
+$lines = explode( "\n", file_get_contents( "includes/libs/mime/mime.types" ) );
 foreach ( $lines as $line ) {
        $exts = explode( " ", $line );
        $mime = array_shift( $exts );
index 60b24a2..f3561b5 100644 (file)
@@ -25,6 +25,7 @@
  * @file
  * @ingroup Maintenance
  */
+use MediaWiki\MediaWikiServices;
 
 if ( !defined( 'RUN_MAINTENANCE_IF_MAIN' ) ) {
        echo "This file must be included after Maintenance.php\n";
@@ -113,12 +114,13 @@ $maintenance->execute();
 $maintenance->globals();
 
 // Perform deferred updates.
+$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+$lbFactory->commitMasterChanges( $maintClass );
 DeferredUpdates::doUpdates();
 
 // log profiling info
 wfLogProfilingData();
 
 // Commit and close up!
-$factory = wfGetLBFactory();
-$factory->commitMasterChanges( 'doMaintenance' );
-$factory->shutdown( $factory::SHUTDOWN_NO_CHRONPROT );
+$lbFactory->commitMasterChanges( 'doMaintenance' );
+$lbFactory->shutdown( $lbFactory::SHUTDOWN_NO_CHRONPROT );
index a8786ef..9ab2532 100644 (file)
@@ -32,9 +32,9 @@
 
        function convertCheckboxesToMulti( $oldContainer, type ) {
                var $fieldLabel = $( '<td>' ),
-               $td = $( '<td>' ),
-               $fieldLabelText = $( '<label>' ),
-               $container;
+                       $td = $( '<td>' ),
+                       $fieldLabelText = $( '<label>' ),
+                       $container;
                if ( type === 'tr' ) {
                        addMulti( $oldContainer, $td );
                        $container = $( '<tr>' );
                return $container;
        }
 
+       function convertCheckboxesWidgetToCapsules( fieldLayout ) {
+               var checkboxesWidget, checkboxesOptions, capsulesOptions, capsulesWidget;
+
+               checkboxesWidget = fieldLayout.fieldWidget;
+               checkboxesOptions = checkboxesWidget.checkboxMultiselectWidget.getItems();
+               capsulesOptions = checkboxesOptions.map( function ( option ) {
+                       return new OO.ui.MenuOptionWidget( {
+                               data: option.getData(),
+                               label: option.getLabel()
+                       } );
+               } );
+               capsulesWidget = new OO.ui.CapsuleMultiselectWidget( {
+                       menu: {
+                               items: capsulesOptions
+                       }
+               } );
+               capsulesWidget.setItemsFromData( checkboxesWidget.getValue() );
+
+               // Data from CapsuleMultiselectWidget will not be submitted with the form, so keep the original
+               // CheckboxMultiselectInputWidget up-to-date.
+               capsulesWidget.on( 'change', function () {
+                       checkboxesWidget.setValue( capsulesWidget.getItemsData() );
+               } );
+
+               // Hide original widget and add new one in its place. This is a bit hacky, since the FieldLayout
+               // still thinks it's connected to the old widget.
+               checkboxesWidget.toggle( false );
+               checkboxesWidget.$element.after( capsulesWidget.$element );
+       }
+
        mw.hook( 'htmlform.enhance' ).add( function ( $root ) {
-               if ( $root.find( '.mw-htmlform-dropdown' ).length ) {
-                       mw.loader.using( 'jquery.chosen', function () {
-                               $root.find( '.mw-htmlform-dropdown' ).each( function () {
-                                       var type = this.nodeName.toLowerCase(),
-                                               $converted = convertCheckboxesToMulti( $( this ), type );
-                                       $converted.find( '.htmlform-chzn-select' ).chosen( { width: 'auto' } );
-                               } );
+               var $dropdowns = $root.find( '.mw-htmlform-field-HTMLMultiSelectField.mw-htmlform-dropdown' );
+               if ( $dropdowns.length ) {
+                       $dropdowns.each( function () {
+                               var $el = $( this ),
+                                       data, modules, extraModules;
+                               if ( $el.is( '[data-ooui]' ) ) {
+                                       // Load 'oojs-ui-widgets' for CapsuleMultiselectWidget
+                                       modules = [ 'mediawiki.htmlform.ooui', 'oojs-ui-widgets' ];
+                                       data = $el.data( 'mw-modules' );
+                                       if ( data ) {
+                                               // We can trust this value, 'data-mw-*' attributes are banned from user content in Sanitizer
+                                               extraModules = data.split( ',' );
+                                               modules.push.apply( modules, extraModules );
+                                       }
+                                       mw.loader.using( modules, function () {
+                                               /*jshint -W024*/
+                                               convertCheckboxesWidgetToCapsules( OO.ui.FieldLayout.static.infuse( $el ) );
+                                       } );
+                               } else {
+                                       mw.loader.using( 'jquery.chosen', function () {
+                                               var type = $el.is( 'tr' ) ? 'tr' : 'div',
+                                                       $converted = convertCheckboxesToMulti( $el, type );
+                                               $converted.find( '.htmlform-chzn-select' ).chosen( { width: 'auto' } );
+                                       } );
+                               }
                        } );
                }
        } );
index 474d541..2ff75d2 100644 (file)
@@ -17,6 +17,9 @@ ul.gallery {
        margin: 2px;
        padding: 2px;
        display: block;
+       width: -moz-fit-content;
+       width: -webkit-fit-content;
+       width: fit-content;
 }
 
 li.gallerycaption {
index a0d6b22..e433c2e 100644 (file)
@@ -26,6 +26,7 @@
  * @ingroup Testing
  */
 use MediaWiki\MediaWikiServices;
+use Wikimedia\ScopedCallback;
 
 /**
  * @ingroup Testing
@@ -175,7 +176,7 @@ class ParserTestRunner {
                // arrays: $setup and $teardown. The code snippets in the $setup array
                // are executed at the end of the method, before it returns, and the
                // code snippets in the $teardown array are executed in reverse order
-               // when the ScopedCallback object is consumed.
+               // when the Wikimedia\ScopedCallback object is consumed.
 
                // Because it is a common operation to save, set and restore global
                // variables, we have an additional convention: when the array key of
index 7437053..9a2a9c9 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use Wikimedia\ScopedCallback;
+
 require __DIR__ . '/../../maintenance/Maintenance.php';
 
 // Make RequestContext::resetMain() happy
index f054c0e..a5e2ac0 100644 (file)
@@ -313,12 +313,14 @@ class MediaWikiServicesTest extends MediaWikiTestCase {
                        'WatchedItemStore' => [ 'WatchedItemStore', WatchedItemStore::class ],
                        'WatchedItemQueryService' => [ 'WatchedItemQueryService', WatchedItemQueryService::class ],
                        'CryptRand' => [ 'CryptRand', CryptRand::class ],
+                       'CryptHKDF' => [ 'CryptHKDF', CryptHKDF::class ],
                        'MediaHandlerFactory' => [ 'MediaHandlerFactory', MediaHandlerFactory::class ],
                        'GenderCache' => [ 'GenderCache', GenderCache::class ],
                        'LinkCache' => [ 'LinkCache', LinkCache::class ],
                        'LinkRenderer' => [ 'LinkRenderer', LinkRenderer::class ],
                        'LinkRendererFactory' => [ 'LinkRendererFactory', LinkRendererFactory::class ],
                        '_MediaWikiTitleCodec' => [ '_MediaWikiTitleCodec', MediaWikiTitleCodec::class ],
+                       'MimeAnalyzer' => [ 'MimeAnalyzer', MimeAnalyzer::class ],
                        'TitleFormatter' => [ 'TitleFormatter', TitleFormatter::class ],
                        'TitleParser' => [ 'TitleParser', TitleParser::class ],
                        'ProxyLookup' => [ 'ProxyLookup', ProxyLookup::class ],
diff --git a/tests/phpunit/includes/MimeMagicTest.php b/tests/phpunit/includes/MimeMagicTest.php
deleted file mode 100644 (file)
index e00cf0c..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-class MimeMagicTest extends PHPUnit_Framework_TestCase {
-
-       /** @var MimeMagic */
-       private $mimeMagic;
-
-       function setUp() {
-               $this->mimeMagic = MimeMagic::singleton();
-               parent::setUp();
-       }
-
-       /**
-        * @dataProvider providerImproveTypeFromExtension
-        * @param string $ext File extension (no leading dot)
-        * @param string $oldMime Initially detected MIME
-        * @param string $expectedMime MIME type after taking extension into account
-        */
-       function testImproveTypeFromExtension( $ext, $oldMime, $expectedMime ) {
-               $actualMime = $this->mimeMagic->improveTypeFromExtension( $oldMime, $ext );
-               $this->assertEquals( $expectedMime, $actualMime );
-       }
-
-       function providerImproveTypeFromExtension() {
-               return [
-                       [ 'gif', 'image/gif', 'image/gif' ],
-                       [ 'gif', 'unknown/unknown', 'unknown/unknown' ],
-                       [ 'wrl', 'unknown/unknown', 'model/vrml' ],
-                       [ 'txt', 'text/plain', 'text/plain' ],
-                       [ 'csv', 'text/plain', 'text/csv' ],
-                       [ 'tsv', 'text/plain', 'text/tab-separated-values' ],
-                       [ 'js', 'text/javascript', 'application/javascript' ],
-                       [ 'js', 'application/x-javascript', 'application/javascript' ],
-                       [ 'json', 'text/plain', 'application/json' ],
-                       [ 'foo', 'application/x-opc+zip', 'application/zip' ],
-                       [ 'docx', 'application/x-opc+zip',
-                               'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ],
-                       [ 'djvu', 'image/x-djvu', 'image/vnd.djvu' ],
-                       [ 'wav', 'audio/wav', 'audio/wav' ],
-               ];
-       }
-
-       /**
-        * Test to make sure that encoder=ffmpeg2theora doesn't trigger
-        * MEDIATYPE_VIDEO (bug 63584)
-        */
-       function testOggRecognize() {
-               $oggFile = __DIR__ . '/../data/media/say-test.ogg';
-               $actualType = $this->mimeMagic->getMediaType( $oggFile, 'application/ogg' );
-               $this->assertEquals( $actualType, MEDIATYPE_AUDIO );
-       }
-}
index c51d496..ba47059 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 use MediaWiki\Linker\LinkTarget;
+use Wikimedia\ScopedCallback;
 
 /**
  * @author Addshore
index dc6fc62..13486e2 100644 (file)
@@ -6,6 +6,7 @@ use MediaWiki\Session\SessionInfo;
 use MediaWiki\Session\UserInfo;
 use Psr\Log\LogLevel;
 use StatusValue;
+use Wikimedia\ScopedCallback;
 
 /**
  * @group AuthManager
@@ -184,7 +185,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                $rProp = new \ReflectionProperty( AuthManager::class, 'instance' );
                $rProp->setAccessible( true );
                $old = $rProp->getValue();
-               $cb = new \ScopedCallback( [ $rProp, 'setValue' ], [ $old ] );
+               $cb = new ScopedCallback( [ $rProp, 'setValue' ], [ $old ] );
                $rProp->setValue( null );
 
                $singleton = AuthManager::singleton();
@@ -202,11 +203,11 @@ class AuthManagerTest extends \MediaWikiTestCase {
 
                list( $provider, $reset ) = $this->getMockSessionProvider( false );
                $this->assertFalse( $this->manager->canAuthenticateNow() );
-               \ScopedCallback::consume( $reset );
+               ScopedCallback::consume( $reset );
 
                list( $provider, $reset ) = $this->getMockSessionProvider( true );
                $this->assertTrue( $this->manager->canAuthenticateNow() );
-               \ScopedCallback::consume( $reset );
+               ScopedCallback::consume( $reset );
        }
 
        public function testNormalizeUsername() {
@@ -385,7 +386,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                        $this->unhook( 'SecuritySensitiveOperationStatus' );
                }
 
-               \ScopedCallback::consume( $reset );
+               ScopedCallback::consume( $reset );
        }
 
        public function onSecuritySensitiveOperationStatus( &$status, $operation, $session, $time ) {
@@ -585,7 +586,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                $this->initializeManager();
 
                $context = \RequestContext::getMain();
-               $reset = new \ScopedCallback( [ $context, 'setLanguage' ], [ $context->getLanguage() ] );
+               $reset = new ScopedCallback( [ $context, 'setLanguage' ], [ $context->getLanguage() ] );
                $context->setLanguage( 'de' );
                $this->setMwGlobals( 'wgContLang', \Language::factory( 'zh' ) );
 
@@ -712,7 +713,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                }
                $this->unhook( 'UserLoggedIn' );
                $this->assertNull( $this->request->getSession()->getSecret( 'AuthManager::authnState' ) );
-               \ScopedCallback::consume( $reset );
+               ScopedCallback::consume( $reset );
                $this->initializeManager( true );
 
                // CreatedAccountAuthenticationRequest
@@ -1449,11 +1450,11 @@ class AuthManagerTest extends \MediaWikiTestCase {
                ];
                $block = new \Block( $blockOptions );
                $block->insert();
-               $scopeVariable = new \ScopedCallback( [ $block, 'delete' ] );
+               $scopeVariable = new ScopedCallback( [ $block, 'delete' ] );
                $status = $this->manager->checkAccountCreatePermissions( new \User );
                $this->assertFalse( $status->isOK() );
                $this->assertTrue( $status->hasMessage( 'cantcreateaccount-range-text' ) );
-               \ScopedCallback::consume( $scopeVariable );
+               ScopedCallback::consume( $scopeVariable );
 
                $this->setMwGlobals( [
                        'wgEnableDnsBlacklist' => true,
index e6d3ecf..68f574b 100644 (file)
@@ -152,7 +152,7 @@ class CheckBlocksSecondaryAuthenticationProviderTest extends \MediaWikiTestCase
                ];
                $block = new \Block( $blockOptions );
                $block->insert();
-               $scopeVariable = new \ScopedCallback( [ $block, 'delete' ] );
+               $scopeVariable = new \Wikimedia\ScopedCallback( [ $block, 'delete' ] );
 
                $user = \User::newFromName( 'UTNormalUser' );
                if ( $user->getID() == 0 ) {
index 8161ed4..bc78c08 100644 (file)
@@ -2,6 +2,8 @@
 
 namespace MediaWiki\Auth;
 
+use Wikimedia\ScopedCallback;
+
 /**
  * @group AuthManager
  * @group Database
@@ -70,7 +72,7 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
                        } );
                }
 
-               return new \ScopedCallback( function () {
+               return new ScopedCallback( function () {
                        \Hooks::clear( 'AlternateUserMailer' );
                        \Hooks::register( 'AlternateUserMailer', function () {
                                return false;
@@ -414,7 +416,7 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
 
                $dbw = wfGetDB( DB_MASTER );
                $oldHash = $dbw->selectField( 'user', 'user_newpassword', [ 'user_name' => $cuser ] );
-               $cb = new \ScopedCallback( function () use ( $dbw, $cuser, $oldHash ) {
+               $cb = new ScopedCallback( function () use ( $dbw, $cuser, $oldHash ) {
                        $dbw->update( 'user', [ 'user_newpassword' => $oldHash ], [ 'user_name' => $cuser ] );
                } );
 
@@ -451,7 +453,7 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
                $changeReq->password = $newpass;
                $resetMailer = $this->hookMailer();
                $provider->providerChangeAuthenticationData( $changeReq );
-               \ScopedCallback::consume( $resetMailer );
+               ScopedCallback::consume( $resetMailer );
 
                $loginReq->password = $oldpass;
                $ret = $provider->beginPrimaryAuthentication( $loginReqs );
@@ -573,7 +575,7 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
                        return false;
                } );
                $provider->providerChangeAuthenticationData( $req );
-               \ScopedCallback::consume( $resetMailer );
+               ScopedCallback::consume( $resetMailer );
                $this->assertTrue( $mailed );
 
                $priv = \TestingAccessWrapper::newFromObject( $provider );
@@ -723,7 +725,7 @@ class TemporaryPasswordPrimaryAuthenticationProviderTest extends \MediaWikiTestC
                $this->assertSame( 'byemail', $provider->finishAccountCreation( $user, $creator, $res ) );
                $this->assertTrue( $mailed );
 
-               \ScopedCallback::consume( $resetMailer );
+               ScopedCallback::consume( $resetMailer );
                $this->assertTrue( $mailed );
        }
 
index 3cde3e2..ded5f8f 100644 (file)
@@ -11,22 +11,6 @@ class ComposerJsonTest extends MediaWikiTestCase {
                $this->json2 = "$IP/tests/phpunit/data/composer/new-composer.json";
        }
 
-       public static function provideGetHash() {
-               return [
-                       [ 'json', 'cc6e7fc565b246cb30b0cac103a2b31e' ],
-                       [ 'json2', '19921dd1fc457f1b00561da932432001' ],
-               ];
-       }
-
-       /**
-        * @dataProvider provideGetHash
-        * @covers ComposerJson::getHash
-        */
-       public function testIsHashUpToDate( $file, $expected ) {
-               $json = new ComposerJson( $this->$file );
-               $this->assertEquals( $expected, $json->getHash() );
-       }
-
        /**
         * @covers ComposerJson::__construct
         * @covers ComposerJson::getRequiredDependencies
index 3d5e8d3..eef7e27 100644 (file)
@@ -10,14 +10,6 @@ class ComposerLockTest extends MediaWikiTestCase {
                $this->lock = "$IP/tests/phpunit/data/composer/composer.lock";
        }
 
-       /**
-        * @covers ComposerLock::getHash
-        */
-       public function testGetHash() {
-               $lock = new ComposerLock( $this->lock );
-               $this->assertEquals( 'a3bb80b0ac4c4a31e52574d48c032923', $lock->getHash() );
-       }
-
        /**
         * @covers ComposerLock::__construct
         * @covers ComposerLock::getInstalledDependencies
diff --git a/tests/phpunit/includes/libs/mime/MimeAnalyzerTest.php b/tests/phpunit/includes/libs/mime/MimeAnalyzerTest.php
new file mode 100644 (file)
index 0000000..85927a3
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+class MimeMagicTest extends PHPUnit_Framework_TestCase {
+       /** @var MimeAnalyzer */
+       private $mimeAnalyzer;
+
+       function setUp() {
+               global $IP;
+
+               $this->mimeAnalyzer = new MimeAnalyzer( [
+                       'infoFile' => $IP . "/includes/libs/mime/mime.info",
+                       'typeFile' => $IP . "/includes/libs/mime/mime.types",
+                       'xmlTypes' => [
+                               'http://www.w3.org/2000/svg:svg' => 'image/svg+xml',
+                               'svg' => 'image/svg+xml',
+                               'http://www.lysator.liu.se/~alla/dia/:diagram' => 'application/x-dia-diagram',
+                               'http://www.w3.org/1999/xhtml:html' => 'text/html', // application/xhtml+xml?
+                               'html' => 'text/html', // application/xhtml+xml?
+                       ]
+               ] );
+               parent::setUp();
+       }
+
+       /**
+        * @dataProvider providerImproveTypeFromExtension
+        * @param string $ext File extension (no leading dot)
+        * @param string $oldMime Initially detected MIME
+        * @param string $expectedMime MIME type after taking extension into account
+        */
+       function testImproveTypeFromExtension( $ext, $oldMime, $expectedMime ) {
+               $actualMime = $this->mimeAnalyzer->improveTypeFromExtension( $oldMime, $ext );
+               $this->assertEquals( $expectedMime, $actualMime );
+       }
+
+       function providerImproveTypeFromExtension() {
+               return [
+                       [ 'gif', 'image/gif', 'image/gif' ],
+                       [ 'gif', 'unknown/unknown', 'unknown/unknown' ],
+                       [ 'wrl', 'unknown/unknown', 'model/vrml' ],
+                       [ 'txt', 'text/plain', 'text/plain' ],
+                       [ 'csv', 'text/plain', 'text/csv' ],
+                       [ 'tsv', 'text/plain', 'text/tab-separated-values' ],
+                       [ 'js', 'text/javascript', 'application/javascript' ],
+                       [ 'js', 'application/x-javascript', 'application/javascript' ],
+                       [ 'json', 'text/plain', 'application/json' ],
+                       [ 'foo', 'application/x-opc+zip', 'application/zip' ],
+                       [ 'docx', 'application/x-opc+zip',
+                               'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ],
+                       [ 'djvu', 'image/x-djvu', 'image/vnd.djvu' ],
+                       [ 'wav', 'audio/wav', 'audio/wav' ],
+               ];
+       }
+
+       /**
+        * Test to make sure that encoder=ffmpeg2theora doesn't trigger
+        * MEDIATYPE_VIDEO (bug 63584)
+        */
+       function testOggRecognize() {
+               $oggFile = __DIR__ . '/../../../data/media/say-test.ogg';
+               $actualType = $this->mimeAnalyzer->getMediaType( $oggFile, 'application/ogg' );
+               $this->assertEquals( $actualType, MEDIATYPE_AUDIO );
+       }
+}
index 9f4e1fa..5f1bf0c 100644 (file)
@@ -1,5 +1,7 @@
 <?php
 
+use Wikimedia\ScopedCallback;
+
 class WikiCategoryPageTest extends MediaWikiLangTestCase {
 
        /**
index b38c98d..c920982 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+use Wikimedia\ScopedCallback;
 
 /**
  * This is the TestCase subclass for running a single parser test via the
index 799a97b..34e5e44 100644 (file)
@@ -21,7 +21,7 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
                        }
                        return false;
                } );
-               $reset[] = new \ScopedCallback( 'restore_error_handler' );
+               $reset[] = new \Wikimedia\ScopedCallback( 'restore_error_handler' );
 
                $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                $rProp->setAccessible( true );
@@ -30,7 +30,7 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
                        $oldManager = $old->manager;
                        $oldStore = $old->store;
                        $oldLogger = $old->logger;
-                       $reset[] = new \ScopedCallback(
+                       $reset[] = new \Wikimedia\ScopedCallback(
                                [ PHPSessionHandler::class, 'install' ],
                                [ $oldManager, $oldStore, $oldLogger ]
                        );
@@ -49,7 +49,7 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
 
                $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                $rProp->setAccessible( true );
-               $reset = new \ScopedCallback( [ $rProp, 'setValue' ], [ $rProp->getValue() ] );
+               $reset = new \Wikimedia\ScopedCallback( [ $rProp, 'setValue' ], [ $rProp->getValue() ] );
                $rProp->setValue( $handler );
 
                $handler->setEnableFlags( 'enable' );
@@ -123,7 +123,7 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
                ] );
                PHPSessionHandler::install( $manager );
                $wrap = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
-               $reset[] = new \ScopedCallback(
+               $reset[] = new \Wikimedia\ScopedCallback(
                        [ $wrap, 'setEnableFlags' ],
                        [ $wrap->enable ? $wrap->warn ? 'warn' : 'enable' : 'disable' ]
                );
@@ -326,7 +326,7 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
                \TestingAccessWrapper::newFromObject( $handler )->setEnableFlags( 'disable' );
                $oldValue = $rProp->getValue();
                $rProp->setValue( $handler );
-               $reset = new \ScopedCallback( [ $rProp, 'setValue' ], [ $oldValue ] );
+               $reset = new \Wikimedia\ScopedCallback( [ $rProp, 'setValue' ], [ $oldValue ] );
 
                call_user_func_array( [ $handler, $method ], $args );
        }
index a3d5de7..8a0adba 100644 (file)
@@ -464,7 +464,7 @@ class SessionBackendTest extends MediaWikiTestCase {
                // Save happens when delay is consumed
                $this->onSessionMetadataCalled = false;
                $priv->metaDirty = true;
-               \ScopedCallback::consume( $delay );
+               \Wikimedia\ScopedCallback::consume( $delay );
                $this->assertTrue( $this->onSessionMetadataCalled );
 
                // Test multiple delays
@@ -475,11 +475,11 @@ class SessionBackendTest extends MediaWikiTestCase {
                $priv->metaDirty = true;
                $priv->autosave();
                $this->assertFalse( $this->onSessionMetadataCalled );
-               \ScopedCallback::consume( $delay3 );
+               \Wikimedia\ScopedCallback::consume( $delay3 );
                $this->assertFalse( $this->onSessionMetadataCalled );
-               \ScopedCallback::consume( $delay1 );
+               \Wikimedia\ScopedCallback::consume( $delay1 );
                $this->assertFalse( $this->onSessionMetadataCalled );
-               \ScopedCallback::consume( $delay2 );
+               \Wikimedia\ScopedCallback::consume( $delay2 );
                $this->assertTrue( $this->onSessionMetadataCalled );
        }
 
@@ -822,7 +822,7 @@ class SessionBackendTest extends MediaWikiTestCase {
                        $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                        $rProp->setAccessible( true );
                        $handler = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
-                       $resetHandler = new \ScopedCallback( function () use ( $handler ) {
+                       $resetHandler = new \Wikimedia\ScopedCallback( function () use ( $handler ) {
                                session_write_close();
                                $handler->enable = false;
                        } );
@@ -862,7 +862,7 @@ class SessionBackendTest extends MediaWikiTestCase {
                        $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                        $rProp->setAccessible( true );
                        $handler = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
-                       $resetHandler = new \ScopedCallback( function () use ( $handler ) {
+                       $resetHandler = new \Wikimedia\ScopedCallback( function () use ( $handler ) {
                                session_write_close();
                                $handler->enable = false;
                        } );
@@ -898,7 +898,7 @@ class SessionBackendTest extends MediaWikiTestCase {
                        $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                        $rProp->setAccessible( true );
                        $handler = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
-                       $resetHandler = new \ScopedCallback( function () use ( $handler ) {
+                       $resetHandler = new \Wikimedia\ScopedCallback( function () use ( $handler ) {
                                session_write_close();
                                $handler->enable = false;
                        } );
index 1ebb07c..6273f47 100644 (file)
@@ -62,7 +62,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                $rProp->setAccessible( true );
                $handler = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
                $oldEnable = $handler->enable;
-               $reset[] = new \ScopedCallback( function () use ( $handler, $oldEnable ) {
+               $reset[] = new \Wikimedia\ScopedCallback( function () use ( $handler, $oldEnable ) {
                        if ( $handler->enable ) {
                                session_write_close();
                        }
index 0cc8ebf..f00de55 100644 (file)
@@ -45,7 +45,7 @@ class TestUtils {
                        PHPSessionHandler::install( $manager );
                }
 
-               return new \ScopedCallback( function () use ( &$reset, $oldInstance ) {
+               return new \Wikimedia\ScopedCallback( function () use ( &$reset, $oldInstance ) {
                        foreach ( $reset as &$arr ) {
                                $arr[0]->setValue( $arr[1] );
                        }
index 3d407fb..145ffb3 100644 (file)
@@ -1,4 +1,6 @@
 <?php
+use Wikimedia\ScopedCallback;
+
 /**
  * Factory for handling the special page list and generating SpecialPage objects.
  *
index 3310d02..074045d 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-class SpecialBooksourcesTest extends MediaWikiTestCase {
+class SpecialBooksourcesTest extends SpecialPageTestBase {
        public static function provideISBNs() {
                return [
                        [ '978-0-300-14424-6', true ],
@@ -33,4 +33,19 @@ class SpecialBooksourcesTest extends MediaWikiTestCase {
        public function testIsValidISBN( $isbn, $isValid ) {
                $this->assertSame( $isValid, SpecialBookSources::isValidISBN( $isbn ) );
        }
+
+       protected function newSpecialPage() {
+               return new SpecialBookSources();
+       }
+
+       /**
+        * @covers SpecialBookSources::execute
+        */
+       public function testExecute() {
+               list( $html, ) = $this->executeSpecialPage( 'Invalid', null, 'qqx' );
+               $this->assertContains( '(booksources-invalid-isbn)', $html );
+               list( $html, ) = $this->executeSpecialPage( '0-7475-3269-9', null, 'qqx' );
+               $this->assertNotContains( '(booksources-invalid-isbn)', $html );
+               $this->assertContains( '(booksources-text)', $html );
+       }
 }
index cb27fde..81c84e8 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 use MediaWiki\Session\SessionManager;
+use Wikimedia\ScopedCallback;
 
 /**
  * @covers BotPassword
index 4284a77..5a7fc48 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+use Wikimedia\ScopedCallback;
 
 /**
  * The UnitTest must be either a class that inherits from MediaWikiTestCase