Merge "Display error if Installer->execute() doesn't return a good status object"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 10 Sep 2019 18:42:57 +0000 (18:42 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 10 Sep 2019 18:42:57 +0000 (18:42 +0000)
139 files changed:
.phpcs.xml
RELEASE-NOTES-1.34
autoload.php
docs/hooks.txt
includes/DefaultSettings.php
includes/MovePage.php
includes/Revision.php
includes/Revision/RevisionStore.php
includes/Setup.php
includes/api/ApiSetNotificationTimestamp.php
includes/api/i18n/ar.json
includes/api/i18n/fr.json
includes/api/i18n/pl.json
includes/api/i18n/zh-hant.json
includes/cache/LinkCache.php
includes/cache/localisation/LCStoreDB.php
includes/deferred/LinksUpdate.php
includes/externalstore/ExternalStoreDB.php
includes/installer/i18n/ia.json
includes/installer/i18n/ja.json
includes/installer/i18n/pl.json
includes/jobqueue/jobs/RefreshLinksJob.php
includes/libs/filebackend/FSFileBackend.php
includes/libs/filebackend/FileBackendStore.php
includes/libs/filebackend/fileophandle/FileBackendStoreOpHandle.php
includes/page/WikiPage.php
includes/preferences/DefaultPreferencesFactory.php
includes/resourceloader/ResourceLoader.php
includes/session/SessionManager.php
includes/session/SessionOverflowException.php [new file with mode: 0644]
includes/specialpage/LoginSignupSpecialPage.php
includes/specialpage/QueryPage.php
includes/specialpage/SpecialPageFactory.php
includes/specials/SpecialAncientPages.php [new file with mode: 0644]
includes/specials/SpecialAncientpages.php [deleted file]
includes/specials/SpecialBlockList.php
includes/specials/SpecialBrokenRedirects.php
includes/specials/SpecialConfirmEmail.php [new file with mode: 0644]
includes/specials/SpecialConfirmemail.php [deleted file]
includes/specials/SpecialDeadendPages.php [new file with mode: 0644]
includes/specials/SpecialDeadendpages.php [deleted file]
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialDoubleRedirects.php
includes/specials/SpecialEmailInvalidate.php
includes/specials/SpecialFewestRevisions.php [new file with mode: 0644]
includes/specials/SpecialFewestrevisions.php [deleted file]
includes/specials/SpecialFileDuplicateSearch.php
includes/specials/SpecialLinkSearch.php
includes/specials/SpecialListDuplicatedFiles.php
includes/specials/SpecialListRedirects.php [new file with mode: 0644]
includes/specials/SpecialListredirects.php [deleted file]
includes/specials/SpecialLonelyPages.php [new file with mode: 0644]
includes/specials/SpecialLonelypages.php [deleted file]
includes/specials/SpecialLongPages.php [new file with mode: 0644]
includes/specials/SpecialLongpages.php [deleted file]
includes/specials/SpecialMIMESearch.php [new file with mode: 0644]
includes/specials/SpecialMIMEsearch.php [deleted file]
includes/specials/SpecialMediaStatistics.php
includes/specials/SpecialMostCategories.php [new file with mode: 0644]
includes/specials/SpecialMostInterwikis.php [new file with mode: 0644]
includes/specials/SpecialMostLinked.php [new file with mode: 0644]
includes/specials/SpecialMostLinkedCategories.php [new file with mode: 0644]
includes/specials/SpecialMostLinkedTemplates.php [new file with mode: 0644]
includes/specials/SpecialMostRevisions.php [new file with mode: 0644]
includes/specials/SpecialMostcategories.php [deleted file]
includes/specials/SpecialMostinterwikis.php [deleted file]
includes/specials/SpecialMostlinked.php [deleted file]
includes/specials/SpecialMostlinkedcategories.php [deleted file]
includes/specials/SpecialMostlinkedtemplates.php [deleted file]
includes/specials/SpecialMostrevisions.php [deleted file]
includes/specials/SpecialNewFiles.php [new file with mode: 0644]
includes/specials/SpecialNewimages.php [deleted file]
includes/specials/SpecialShortPages.php [new file with mode: 0644]
includes/specials/SpecialShortpages.php [deleted file]
includes/specials/SpecialUncategorizedCategories.php [new file with mode: 0644]
includes/specials/SpecialUncategorizedImages.php [new file with mode: 0644]
includes/specials/SpecialUncategorizedPages.php [new file with mode: 0644]
includes/specials/SpecialUncategorizedTemplates.php [new file with mode: 0644]
includes/specials/SpecialUncategorizedcategories.php [deleted file]
includes/specials/SpecialUncategorizedimages.php [deleted file]
includes/specials/SpecialUncategorizedpages.php [deleted file]
includes/specials/SpecialUncategorizedtemplates.php [deleted file]
includes/specials/SpecialUndelete.php
includes/specials/SpecialUnusedCategories.php [new file with mode: 0644]
includes/specials/SpecialUnusedImages.php [new file with mode: 0644]
includes/specials/SpecialUnusedTemplates.php [new file with mode: 0644]
includes/specials/SpecialUnusedcategories.php [deleted file]
includes/specials/SpecialUnusedimages.php [deleted file]
includes/specials/SpecialUnusedtemplates.php [deleted file]
includes/specials/SpecialUnwatchedPages.php [new file with mode: 0644]
includes/specials/SpecialUnwatchedpages.php [deleted file]
includes/specials/SpecialWantedCategories.php [new file with mode: 0644]
includes/specials/SpecialWantedTemplates.php [new file with mode: 0644]
includes/specials/SpecialWantedcategories.php [deleted file]
includes/specials/SpecialWantedtemplates.php [deleted file]
includes/specials/SpecialWithoutInterwiki.php [new file with mode: 0644]
includes/specials/SpecialWithoutinterwiki.php [deleted file]
includes/specials/pagers/ActiveUsersPager.php
includes/specials/pagers/AllMessagesTablePager.php
includes/specials/pagers/MergeHistoryPager.php
includes/specials/pagers/ProtectedTitlesPager.php
includes/specials/pagers/UsersPager.php
includes/user/User.php
includes/widget/CheckMatrixWidget.php
includes/widget/ComplexTitleInputWidget.php
includes/widget/NamespaceInputWidget.php
includes/widget/SelectWithInputWidget.php
includes/widget/SizeFilterWidget.php
includes/widget/TagMultiselectWidget.php
languages/i18n/cs.json
languages/i18n/diq.json
languages/i18n/en.json
languages/i18n/exif/pl.json
languages/i18n/fr.json
languages/i18n/gom-deva.json
languages/i18n/gom-latn.json
languages/i18n/hr.json
languages/i18n/ja.json
languages/i18n/mk.json
languages/i18n/pl.json
languages/i18n/qqq.json
languages/i18n/sv.json
languages/i18n/szl.json
languages/i18n/tt-cyrl.json
languages/i18n/zh-hant.json
maintenance/cleanupTitles.php
maintenance/storage/blobs.sql
maintenance/storage/checkStorage.php
maintenance/userOptions.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/api/ApiDeleteTest.php
tests/phpunit/includes/api/ApiRevisionDeleteTest.php
tests/phpunit/includes/session/SessionManagerTest.php
tests/phpunit/includes/specials/QueryAllSpecialPagesTest.php
tests/phpunit/includes/specials/SpecialMIMESearchTest.php
tests/phpunit/includes/specials/SpecialShortPagesTest.php [new file with mode: 0644]
tests/phpunit/includes/specials/SpecialShortpagesTest.php [deleted file]
tests/phpunit/includes/specials/SpecialUncategorizedCategoriesTest.php [new file with mode: 0644]
tests/phpunit/includes/specials/UncategorizedCategoriesPageTest.php [deleted file]

index 9f11ebc..f971881 100644 (file)
                        Whitelist existing violations, but enable the sniff to prevent
                        any new occurrences.
                -->
-               <exclude-pattern>*/includes/specials/SpecialMostinterwikis\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialAncientpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialBrokenRedirects\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialConfirmemail\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialDeadendpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialDeletedContributions\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialDoubleRedirects\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialEmailInvalidate\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialFewestrevisions\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialFileDuplicateSearch\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialLinkSearch\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialListDuplicatedFiles\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialListredirects\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialLonelypages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialLongpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMIMEsearch\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMediaStatistics\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostcategories\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialMostimages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostlinked\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostlinkedcategories\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostlinkedtemplates\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialMostrevisions\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialMovepage\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialNewimages\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialRandompage\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialShortpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUncategorizedcategories\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUncategorizedimages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUncategorizedpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUncategorizedtemplates\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUnusedcategories\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUnusedimages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUnusedtemplates\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialUnwatchedpages\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialUserrights\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialWantedcategories\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialWantedfiles\.php</exclude-pattern>
                <exclude-pattern>*/includes/specials/SpecialWantedpages\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialWantedtemplates\.php</exclude-pattern>
-               <exclude-pattern>*/includes/specials/SpecialWithoutinterwiki\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/CodeCleanerGlobalsPass.inc</exclude-pattern>
                <exclude-pattern>*/maintenance/archives/upgradeLogging\.php</exclude-pattern>
                <exclude-pattern>*/maintenance/benchmarks/bench_HTTP_HTTPS\.php</exclude-pattern>
index 2e220af..b8c9102 100644 (file)
@@ -190,6 +190,34 @@ because of Phabricator reports.
   * CryptRand class
   * CryptRand service
   * Functions of the MWCryptRand class: singleton(), wasStrong() and generate().
+* Various Special Page PHP Classes were renamed (mostly casing changes):
+  * SpecialAncientpages => SpecialAncientPages
+  * SpecialConfirmemail => SpecialConfirmEmail
+  * SpecialDeadendpages => SpecialDeadendPages
+  * SpecialFewestrevisions => SpecialFewestRevisions
+  * SpecialListredirects => SpecialListRedirects
+  * SpecialLonelypages => SpecialLonelyPages
+  * SpecialLongpages => SpecialLongPages
+  * SpecialMIMEsearch => SpecialMIMESearch
+  * SpecialMostcategories => SpecialMostCategories
+  * SpecialMostinterwikis => SpecialMostInterwikis
+  * SpecialMostlinked => SpecialMostLinked
+  * SpecialMostlinkedcategories => SpecialMostLinkedCategories
+  * SpecialMostlinkedtemplates => SpecialMostLinkedTemplates
+  * SpecialMostrevisions => SpecialMostRevisions
+  * SpecialNewimages => SpecialNewFiles
+  * SpecialShortpages => SpecialShortPages
+  * SpecialUncategorizedcategories => SpecialUncategorizedCategories
+  * SpecialUncategorizedimages => SpecialUncategorizedImages
+  * SpecialUncategorizedpages => SpecialUncategorizedPages
+  * SpecialUncategorizedtemplates => SpecialUncategorizedTemplates
+  * SpecialUnusedcategories => SpecialUnusedCategories
+  * SpecialUnusedimages => SpecialUnusedImages
+  * SpecialUnusedtemplates => SpecialUnusedTemplates
+  * SpecialUnwatchedpages => SpecialUnwatchedPages
+  * SpecialWantedcategories => SpecialWantedCategories
+  * SpecialWantedtemplates => SpecialWantedTemplates
+  * SpecialWithoutinterwiki => SpecialWithoutInterwiki
 * Language::setCode, deprecated in 1.32, was removed. Use Language::factory to
   create a new Language object with a different language code.
 * MWNamespace::clearCaches() has been removed.  So has the $rebuild parameter
@@ -532,6 +560,8 @@ because of Phabricator reports.
   be used instead.
 * The UserIsHidden hook is deprecated. Use GetUserBlock instead, and add a
   system block that hides the user.
+* The GetBlockedStatus hook is deprecated. Use GetUserBlock instead, to add or
+  remove a block.
 
 === Other changes in 1.34 ===
 * …
index 87b2bb9..f95e001 100644 (file)
@@ -20,7 +20,6 @@ $wgAutoloadLocalClasses = [
        'AllMessagesTablePager' => __DIR__ . '/includes/specials/pagers/AllMessagesTablePager.php',
        'AllTrans' => __DIR__ . '/maintenance/language/alltrans.php',
        'AlphabeticPager' => __DIR__ . '/includes/pager/AlphabeticPager.php',
-       'AncientPagesPage' => __DIR__ . '/includes/specials/SpecialAncientpages.php',
        'AnsiTermColorer' => __DIR__ . '/maintenance/term/MWTerm.php',
        'ApiAMCreateAccount' => __DIR__ . '/includes/api/ApiAMCreateAccount.php',
        'ApiAuthManagerHelper' => __DIR__ . '/includes/api/ApiAuthManagerHelper.php',
@@ -215,7 +214,6 @@ $wgAutoloadLocalClasses = [
        'BlockLogFormatter' => __DIR__ . '/includes/logging/BlockLogFormatter.php',
        'BmpHandler' => __DIR__ . '/includes/media/BmpHandler.php',
        'BotPassword' => __DIR__ . '/includes/user/BotPassword.php',
-       'BrokenRedirectsPage' => __DIR__ . '/includes/specials/SpecialBrokenRedirects.php',
        'BufferingStatsdDataFactory' => __DIR__ . '/includes/libs/stats/BufferingStatsdDataFactory.php',
        'CLIParser' => __DIR__ . '/maintenance/parse.php',
        'CSSMin' => __DIR__ . '/includes/libs/CSSMin.php',
@@ -366,7 +364,6 @@ $wgAutoloadLocalClasses = [
        'DateFormats' => __DIR__ . '/maintenance/language/date-formats.php',
        'DateFormatter' => __DIR__ . '/includes/parser/DateFormatter.php',
        'DateFormatterFactory' => __DIR__ . '/includes/parser/DateFormatterFactory.php',
-       'DeadendPagesPage' => __DIR__ . '/includes/specials/SpecialDeadendpages.php',
        'DeduplicateArchiveRevId' => __DIR__ . '/maintenance/deduplicateArchiveRevId.php',
        'DeferrableCallback' => __DIR__ . '/includes/deferred/DeferrableCallback.php',
        'DeferrableUpdate' => __DIR__ . '/includes/deferred/DeferrableUpdate.php',
@@ -388,7 +385,6 @@ $wgAutoloadLocalClasses = [
        'DeletePageJob' => __DIR__ . '/includes/jobqueue/jobs/DeletePageJob.php',
        'DeleteSelfExternals' => __DIR__ . '/maintenance/deleteSelfExternals.php',
        'DeletedContribsPager' => __DIR__ . '/includes/specials/pagers/DeletedContribsPager.php',
-       'DeletedContributionsPage' => __DIR__ . '/includes/specials/SpecialDeletedContributions.php',
        'DependencyWrapper' => __DIR__ . '/includes/cache/dependency/DependencyWrapper.php',
        'DeprecatedGlobal' => __DIR__ . '/includes/DeprecatedGlobal.php',
        'DeprecatedInterfaceFinder' => __DIR__ . '/maintenance/findDeprecated.php',
@@ -414,7 +410,6 @@ $wgAutoloadLocalClasses = [
        'DjVuImage' => __DIR__ . '/includes/media/DjVuImage.php',
        'DnsSrvDiscoverer' => __DIR__ . '/includes/libs/DnsSrvDiscoverer.php',
        'DoubleRedirectJob' => __DIR__ . '/includes/jobqueue/jobs/DoubleRedirectJob.php',
-       'DoubleRedirectsPage' => __DIR__ . '/includes/specials/SpecialDoubleRedirects.php',
        'DummyLinker' => __DIR__ . '/includes/DummyLinker.php',
        'DummySearchIndexFieldDefinition' => __DIR__ . '/includes/search/DummySearchIndexFieldDefinition.php',
        'DummyTermColorer' => __DIR__ . '/maintenance/term/MWTerm.php',
@@ -447,8 +442,6 @@ $wgAutoloadLocalClasses = [
        'EditPage' => __DIR__ . '/includes/EditPage.php',
        'EditWatchlistCheckboxSeriesField' => __DIR__ . '/includes/specials/formfields/EditWatchlistCheckboxSeriesField.php',
        'EditWatchlistNormalHTMLForm' => __DIR__ . '/includes/specials/forms/EditWatchlistNormalHTMLForm.php',
-       'EmailConfirmation' => __DIR__ . '/includes/specials/SpecialConfirmemail.php',
-       'EmailInvalidation' => __DIR__ . '/includes/specials/SpecialEmailInvalidate.php',
        'EmailNotification' => __DIR__ . '/includes/mail/EmailNotification.php',
        'EmaillingJob' => __DIR__ . '/includes/jobqueue/jobs/EmaillingJob.php',
        'EmptyBagOStuff' => __DIR__ . '/includes/libs/objectcache/EmptyBagOStuff.php',
@@ -505,7 +498,6 @@ $wgAutoloadLocalClasses = [
        'FeedItem' => __DIR__ . '/includes/changes/FeedItem.php',
        'FeedUtils' => __DIR__ . '/includes/FeedUtils.php',
        'FetchText' => __DIR__ . '/maintenance/fetchText.php',
-       'FewestrevisionsPage' => __DIR__ . '/includes/specials/SpecialFewestrevisions.php',
        'Field' => __DIR__ . '/includes/libs/rdbms/field/Field.php',
        'File' => __DIR__ . '/includes/filerepo/file/File.php',
        'FileAwareNodeVisitor' => __DIR__ . '/maintenance/findDeprecated.php',
@@ -525,7 +517,6 @@ $wgAutoloadLocalClasses = [
        'FileContentsHasher' => __DIR__ . '/includes/utils/FileContentsHasher.php',
        'FileDeleteForm' => __DIR__ . '/includes/FileDeleteForm.php',
        'FileDependency' => __DIR__ . '/includes/cache/dependency/FileDependency.php',
-       'FileDuplicateSearchPage' => __DIR__ . '/includes/specials/SpecialFileDuplicateSearch.php',
        'FileJournal' => __DIR__ . '/includes/libs/filebackend/filejournal/FileJournal.php',
        'FileOp' => __DIR__ . '/includes/libs/filebackend/fileop/FileOp.php',
        'FileOpBatch' => __DIR__ . '/includes/libs/filebackend/FileOpBatch.php',
@@ -785,14 +776,11 @@ $wgAutoloadLocalClasses = [
        'LinkCache' => __DIR__ . '/includes/cache/LinkCache.php',
        'LinkFilter' => __DIR__ . '/includes/LinkFilter.php',
        'LinkHolderArray' => __DIR__ . '/includes/parser/LinkHolderArray.php',
-       'LinkSearchPage' => __DIR__ . '/includes/specials/SpecialLinkSearch.php',
        'Linker' => __DIR__ . '/includes/Linker.php',
        'LinksDeletionUpdate' => __DIR__ . '/includes/deferred/LinksDeletionUpdate.php',
        'LinksUpdate' => __DIR__ . '/includes/deferred/LinksUpdate.php',
-       'ListDuplicatedFilesPage' => __DIR__ . '/includes/specials/SpecialListDuplicatedFiles.php',
        'ListToggle' => __DIR__ . '/includes/ListToggle.php',
        'ListVariants' => __DIR__ . '/maintenance/language/listVariants.php',
-       'ListredirectsPage' => __DIR__ . '/includes/specials/SpecialListredirects.php',
        'LoadBalancer' => __DIR__ . '/includes/libs/rdbms/loadbalancer/LoadBalancer.php',
        'LoadBalancerSingle' => __DIR__ . '/includes/libs/rdbms/loadbalancer/LoadBalancerSingle.php',
        'LocalFile' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
@@ -818,9 +806,6 @@ $wgAutoloadLocalClasses = [
        'LoggedUpdateMaintenance' => __DIR__ . '/maintenance/Maintenance.php',
        'LoginHelper' => __DIR__ . '/includes/specials/helpers/LoginHelper.php',
        'LoginSignupSpecialPage' => __DIR__ . '/includes/specialpage/LoginSignupSpecialPage.php',
-       'LonelyPagesPage' => __DIR__ . '/includes/specials/SpecialLonelypages.php',
-       'LongPagesPage' => __DIR__ . '/includes/specials/SpecialLongpages.php',
-       'MIMEsearchPage' => __DIR__ . '/includes/specials/SpecialMIMEsearch.php',
        'MSCompoundFileReader' => __DIR__ . '/includes/libs/mime/MSCompoundFileReader.php',
        'MWCallableUpdate' => __DIR__ . '/includes/deferred/MWCallableUpdate.php',
        'MWCallbackStream' => __DIR__ . '/includes/http/MWCallbackStream.php',
@@ -867,7 +852,6 @@ $wgAutoloadLocalClasses = [
        'McrUndoAction' => __DIR__ . '/includes/actions/McrUndoAction.php',
        'MediaHandler' => __DIR__ . '/includes/media/MediaHandler.php',
        'MediaHandlerFactory' => __DIR__ . '/includes/media/MediaHandlerFactory.php',
-       'MediaStatisticsPage' => __DIR__ . '/includes/specials/SpecialMediaStatistics.php',
        'MediaTransformError' => __DIR__ . '/includes/media/MediaTransformError.php',
        'MediaTransformInvalidParametersException' => __DIR__ . '/includes/media/MediaTransformInvalidParametersException.php',
        'MediaTransformOutput' => __DIR__ . '/includes/media/MediaTransformOutput.php',
@@ -1002,13 +986,7 @@ $wgAutoloadLocalClasses = [
        'MigrateUserGroup' => __DIR__ . '/maintenance/migrateUserGroup.php',
        'MimeAnalyzer' => __DIR__ . '/includes/libs/mime/MimeAnalyzer.php',
        'MinifyScript' => __DIR__ . '/maintenance/minify.php',
-       'MostcategoriesPage' => __DIR__ . '/includes/specials/SpecialMostcategories.php',
        'MostimagesPage' => __DIR__ . '/includes/specials/SpecialMostimages.php',
-       'MostinterwikisPage' => __DIR__ . '/includes/specials/SpecialMostinterwikis.php',
-       'MostlinkedCategoriesPage' => __DIR__ . '/includes/specials/SpecialMostlinkedcategories.php',
-       'MostlinkedPage' => __DIR__ . '/includes/specials/SpecialMostlinked.php',
-       'MostlinkedTemplatesPage' => __DIR__ . '/includes/specials/SpecialMostlinkedtemplates.php',
-       'MostrevisionsPage' => __DIR__ . '/includes/specials/SpecialMostrevisions.php',
        'MoveBatch' => __DIR__ . '/maintenance/moveBatch.php',
        'MoveFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/MoveFileOp.php',
        'MoveLogFormatter' => __DIR__ . '/includes/logging/MoveLogFormatter.php',
@@ -1331,7 +1309,6 @@ $wgAutoloadLocalClasses = [
        'SerializedValueContainer' => __DIR__ . '/includes/libs/objectcache/serialized/SerializedValueContainer.php',
        'SevenZipStream' => __DIR__ . '/maintenance/includes/SevenZipStream.php',
        'ShiConverter' => __DIR__ . '/languages/classes/LanguageShi.php',
-       'ShortPagesPage' => __DIR__ . '/includes/specials/SpecialShortpages.php',
        'ShowJobs' => __DIR__ . '/maintenance/showJobs.php',
        'ShowSiteStats' => __DIR__ . '/maintenance/showSiteStats.php',
        'Site' => __DIR__ . '/includes/site/Site.php',
@@ -1358,6 +1335,7 @@ $wgAutoloadLocalClasses = [
        'SpecialAllMessages' => __DIR__ . '/includes/specials/SpecialAllMessages.php',
        'SpecialAllMyUploads' => __DIR__ . '/includes/specials/redirects/SpecialAllMyUploads.php',
        'SpecialAllPages' => __DIR__ . '/includes/specials/SpecialAllPages.php',
+       'SpecialAncientPages' => __DIR__ . '/includes/specials/SpecialAncientPages.php',
        'SpecialApiHelp' => __DIR__ . '/includes/specials/SpecialApiHelp.php',
        'SpecialApiSandbox' => __DIR__ . '/includes/specials/SpecialApiSandbox.php',
        'SpecialAutoblockList' => __DIR__ . '/includes/specials/SpecialAutoblockList.php',
@@ -1366,6 +1344,7 @@ $wgAutoloadLocalClasses = [
        'SpecialBlockList' => __DIR__ . '/includes/specials/SpecialBlockList.php',
        'SpecialBookSources' => __DIR__ . '/includes/specials/SpecialBookSources.php',
        'SpecialBotPasswords' => __DIR__ . '/includes/specials/SpecialBotPasswords.php',
+       'SpecialBrokenRedirects' => __DIR__ . '/includes/specials/SpecialBrokenRedirects.php',
        'SpecialCachedPage' => __DIR__ . '/includes/specials/SpecialCachedPage.php',
        'SpecialCategories' => __DIR__ . '/includes/specials/SpecialCategories.php',
        'SpecialChangeContentModel' => __DIR__ . '/includes/specials/SpecialChangeContentModel.php',
@@ -1373,35 +1352,55 @@ $wgAutoloadLocalClasses = [
        'SpecialChangeEmail' => __DIR__ . '/includes/specials/SpecialChangeEmail.php',
        'SpecialChangePassword' => __DIR__ . '/includes/specials/SpecialChangePassword.php',
        'SpecialComparePages' => __DIR__ . '/includes/specials/SpecialComparePages.php',
+       'SpecialConfirmEmail' => __DIR__ . '/includes/specials/SpecialConfirmEmail.php',
        'SpecialContributions' => __DIR__ . '/includes/specials/SpecialContributions.php',
        'SpecialCreateAccount' => __DIR__ . '/includes/specials/SpecialCreateAccount.php',
+       'SpecialDeadendPages' => __DIR__ . '/includes/specials/SpecialDeadendPages.php',
+       'SpecialDeletedContributions' => __DIR__ . '/includes/specials/SpecialDeletedContributions.php',
        'SpecialDiff' => __DIR__ . '/includes/specials/SpecialDiff.php',
+       'SpecialDoubleRedirects' => __DIR__ . '/includes/specials/SpecialDoubleRedirects.php',
        'SpecialEditTags' => __DIR__ . '/includes/specials/SpecialEditTags.php',
        'SpecialEditWatchlist' => __DIR__ . '/includes/specials/SpecialEditWatchlist.php',
+       'SpecialEmailInvalidate' => __DIR__ . '/includes/specials/SpecialEmailInvalidate.php',
        'SpecialEmailUser' => __DIR__ . '/includes/specials/SpecialEmailUser.php',
        'SpecialExpandTemplates' => __DIR__ . '/includes/specials/SpecialExpandTemplates.php',
        'SpecialExport' => __DIR__ . '/includes/specials/SpecialExport.php',
+       'SpecialFewestRevisions' => __DIR__ . '/includes/specials/SpecialFewestRevisions.php',
+       'SpecialFileDuplicateSearch' => __DIR__ . '/includes/specials/SpecialFileDuplicateSearch.php',
        'SpecialFilepath' => __DIR__ . '/includes/specials/SpecialFilepath.php',
        'SpecialGoToInterwiki' => __DIR__ . '/includes/specials/SpecialGoToInterwiki.php',
        'SpecialImport' => __DIR__ . '/includes/specials/SpecialImport.php',
        'SpecialJavaScriptTest' => __DIR__ . '/includes/specials/SpecialJavaScriptTest.php',
        'SpecialLinkAccounts' => __DIR__ . '/includes/specials/SpecialLinkAccounts.php',
+       'SpecialLinkSearch' => __DIR__ . '/includes/specials/SpecialLinkSearch.php',
        'SpecialListAdmins' => __DIR__ . '/includes/specials/redirects/SpecialListAdmins.php',
        'SpecialListBots' => __DIR__ . '/includes/specials/redirects/SpecialListBots.php',
+       'SpecialListDuplicatedFiles' => __DIR__ . '/includes/specials/SpecialListDuplicatedFiles.php',
        'SpecialListFiles' => __DIR__ . '/includes/specials/SpecialListFiles.php',
        'SpecialListGrants' => __DIR__ . '/includes/specials/SpecialListGrants.php',
        'SpecialListGroupRights' => __DIR__ . '/includes/specials/SpecialListGroupRights.php',
+       'SpecialListRedirects' => __DIR__ . '/includes/specials/SpecialListRedirects.php',
        'SpecialListUsers' => __DIR__ . '/includes/specials/SpecialListUsers.php',
        'SpecialLockdb' => __DIR__ . '/includes/specials/SpecialLockdb.php',
        'SpecialLog' => __DIR__ . '/includes/specials/SpecialLog.php',
+       'SpecialLonelyPages' => __DIR__ . '/includes/specials/SpecialLonelyPages.php',
+       'SpecialLongPages' => __DIR__ . '/includes/specials/SpecialLongPages.php',
+       'SpecialMIMESearch' => __DIR__ . '/includes/specials/SpecialMIMESearch.php',
+       'SpecialMediaStatistics' => __DIR__ . '/includes/specials/SpecialMediaStatistics.php',
        'SpecialMergeHistory' => __DIR__ . '/includes/specials/SpecialMergeHistory.php',
+       'SpecialMostCategories' => __DIR__ . '/includes/specials/SpecialMostCategories.php',
+       'SpecialMostInterwikis' => __DIR__ . '/includes/specials/SpecialMostInterwikis.php',
+       'SpecialMostLinked' => __DIR__ . '/includes/specials/SpecialMostLinked.php',
+       'SpecialMostLinkedCategories' => __DIR__ . '/includes/specials/SpecialMostLinkedCategories.php',
+       'SpecialMostLinkedTemplates' => __DIR__ . '/includes/specials/SpecialMostLinkedTemplates.php',
+       'SpecialMostRevisions' => __DIR__ . '/includes/specials/SpecialMostRevisions.php',
        'SpecialMute' => __DIR__ . '/includes/specials/SpecialMute.php',
        'SpecialMyLanguage' => __DIR__ . '/includes/specials/SpecialMyLanguage.php',
        'SpecialMycontributions' => __DIR__ . '/includes/specials/redirects/SpecialMycontributions.php',
        'SpecialMypage' => __DIR__ . '/includes/specials/redirects/SpecialMypage.php',
        'SpecialMytalk' => __DIR__ . '/includes/specials/redirects/SpecialMytalk.php',
        'SpecialMyuploads' => __DIR__ . '/includes/specials/redirects/SpecialMyuploads.php',
-       'SpecialNewFiles' => __DIR__ . '/includes/specials/SpecialNewimages.php',
+       'SpecialNewFiles' => __DIR__ . '/includes/specials/SpecialNewFiles.php',
        'SpecialNewSection' => __DIR__ . '/includes/specials/SpecialNewSection.php',
        'SpecialNewpages' => __DIR__ . '/includes/specials/SpecialNewpages.php',
        'SpecialPage' => __DIR__ . '/includes/specialpage/SpecialPage.php',
@@ -1429,22 +1428,34 @@ $wgAutoloadLocalClasses = [
        'SpecialRevisionDelete' => __DIR__ . '/includes/specials/SpecialRevisionDelete.php',
        'SpecialRunJobs' => __DIR__ . '/includes/specials/SpecialRunJobs.php',
        'SpecialSearch' => __DIR__ . '/includes/specials/SpecialSearch.php',
+       'SpecialShortPages' => __DIR__ . '/includes/specials/SpecialShortPages.php',
        'SpecialSpecialpages' => __DIR__ . '/includes/specials/SpecialSpecialpages.php',
        'SpecialStatistics' => __DIR__ . '/includes/specials/SpecialStatistics.php',
        'SpecialTags' => __DIR__ . '/includes/specials/SpecialTags.php',
        'SpecialTrackingCategories' => __DIR__ . '/includes/specials/SpecialTrackingCategories.php',
        'SpecialUnblock' => __DIR__ . '/includes/specials/SpecialUnblock.php',
+       'SpecialUncategorizedCategories' => __DIR__ . '/includes/specials/SpecialUncategorizedCategories.php',
+       'SpecialUncategorizedImages' => __DIR__ . '/includes/specials/SpecialUncategorizedImages.php',
+       'SpecialUncategorizedPages' => __DIR__ . '/includes/specials/SpecialUncategorizedPages.php',
+       'SpecialUncategorizedTemplates' => __DIR__ . '/includes/specials/SpecialUncategorizedTemplates.php',
        'SpecialUndelete' => __DIR__ . '/includes/specials/SpecialUndelete.php',
        'SpecialUnlinkAccounts' => __DIR__ . '/includes/specials/SpecialUnlinkAccounts.php',
        'SpecialUnlockdb' => __DIR__ . '/includes/specials/SpecialUnlockdb.php',
+       'SpecialUnusedCategories' => __DIR__ . '/includes/specials/SpecialUnusedCategories.php',
+       'SpecialUnusedImages' => __DIR__ . '/includes/specials/SpecialUnusedImages.php',
+       'SpecialUnusedTemplates' => __DIR__ . '/includes/specials/SpecialUnusedTemplates.php',
+       'SpecialUnwatchedPages' => __DIR__ . '/includes/specials/SpecialUnwatchedPages.php',
        'SpecialUpload' => __DIR__ . '/includes/specials/SpecialUpload.php',
        'SpecialUploadStash' => __DIR__ . '/includes/specials/SpecialUploadStash.php',
        'SpecialUploadStashTooLargeException' => __DIR__ . '/includes/specials/exception/SpecialUploadStashTooLargeException.php',
        'SpecialUserLogin' => __DIR__ . '/includes/specials/SpecialUserLogin.php',
        'SpecialUserLogout' => __DIR__ . '/includes/specials/SpecialUserLogout.php',
        'SpecialVersion' => __DIR__ . '/includes/specials/SpecialVersion.php',
+       'SpecialWantedCategories' => __DIR__ . '/includes/specials/SpecialWantedCategories.php',
+       'SpecialWantedTemplates' => __DIR__ . '/includes/specials/SpecialWantedTemplates.php',
        'SpecialWatchlist' => __DIR__ . '/includes/specials/SpecialWatchlist.php',
        'SpecialWhatLinksHere' => __DIR__ . '/includes/specials/SpecialWhatLinksHere.php',
+       'SpecialWithoutInterwiki' => __DIR__ . '/includes/specials/SpecialWithoutInterwiki.php',
        'SqlBagOStuff' => __DIR__ . '/includes/objectcache/SqlBagOStuff.php',
        'SqlSearchResult' => __DIR__ . '/includes/search/SqlSearchResult.php',
        'SqlSearchResultSet' => __DIR__ . '/includes/search/SqlSearchResultSet.php',
@@ -1517,10 +1528,6 @@ $wgAutoloadLocalClasses = [
        'UDPTransport' => __DIR__ . '/includes/libs/UDPTransport.php',
        'UIDGenerator' => __DIR__ . '/includes/utils/UIDGenerator.php',
        'UcdXmlReader' => __DIR__ . '/maintenance/language/generateCollationData.php',
-       'UncategorizedCategoriesPage' => __DIR__ . '/includes/specials/SpecialUncategorizedcategories.php',
-       'UncategorizedImagesPage' => __DIR__ . '/includes/specials/SpecialUncategorizedimages.php',
-       'UncategorizedPagesPage' => __DIR__ . '/includes/specials/SpecialUncategorizedpages.php',
-       'UncategorizedTemplatesPage' => __DIR__ . '/includes/specials/SpecialUncategorizedtemplates.php',
        'Undelete' => __DIR__ . '/maintenance/undelete.php',
        'UnifiedDiffFormatter' => __DIR__ . '/includes/diff/UnifiedDiffFormatter.php',
        'UnknownContent' => __DIR__ . '/includes/content/UnknownContent.php',
@@ -1529,11 +1536,7 @@ $wgAutoloadLocalClasses = [
        'UnprotectAction' => __DIR__ . '/includes/actions/UnprotectAction.php',
        'UnregisteredLocalFile' => __DIR__ . '/includes/filerepo/file/UnregisteredLocalFile.php',
        'UnsupportedSlotDiffRenderer' => __DIR__ . '/includes/diff/UnsupportedSlotDiffRenderer.php',
-       'UnusedCategoriesPage' => __DIR__ . '/includes/specials/SpecialUnusedcategories.php',
-       'UnusedimagesPage' => __DIR__ . '/includes/specials/SpecialUnusedimages.php',
-       'UnusedtemplatesPage' => __DIR__ . '/includes/specials/SpecialUnusedtemplates.php',
        'UnwatchAction' => __DIR__ . '/includes/actions/UnwatchAction.php',
-       'UnwatchedpagesPage' => __DIR__ . '/includes/specials/SpecialUnwatchedpages.php',
        'UpdateArticleCount' => __DIR__ . '/maintenance/updateArticleCount.php',
        'UpdateCollation' => __DIR__ . '/maintenance/updateCollation.php',
        'UpdateDoubleWidthSearch' => __DIR__ . '/maintenance/updateDoubleWidthSearch.php',
@@ -1597,11 +1600,9 @@ $wgAutoloadLocalClasses = [
        'WANCacheReapUpdate' => __DIR__ . '/includes/deferred/WANCacheReapUpdate.php',
        'WANObjectCache' => __DIR__ . '/includes/libs/objectcache/wancache/WANObjectCache.php',
        'WANObjectCacheReaper' => __DIR__ . '/includes/libs/objectcache/wancache/WANObjectCacheReaper.php',
-       'WantedCategoriesPage' => __DIR__ . '/includes/specials/SpecialWantedcategories.php',
        'WantedFilesPage' => __DIR__ . '/includes/specials/SpecialWantedfiles.php',
        'WantedPagesPage' => __DIR__ . '/includes/specials/SpecialWantedpages.php',
        'WantedQueryPage' => __DIR__ . '/includes/specialpage/WantedQueryPage.php',
-       'WantedTemplatesPage' => __DIR__ . '/includes/specials/SpecialWantedtemplates.php',
        'WatchAction' => __DIR__ . '/includes/actions/WatchAction.php',
        'WatchedItem' => __DIR__ . '/includes/watcheditem/WatchedItem.php',
        'WatchedItemQueryService' => __DIR__ . '/includes/watcheditem/WatchedItemQueryService.php',
@@ -1705,7 +1706,6 @@ $wgAutoloadLocalClasses = [
        'WikitextContentHandler' => __DIR__ . '/includes/content/WikitextContentHandler.php',
        'WikitextLogFormatter' => __DIR__ . '/includes/logging/WikitextLogFormatter.php',
        'WinCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/WinCacheBagOStuff.php',
-       'WithoutInterwikiPage' => __DIR__ . '/includes/specials/SpecialWithoutinterwiki.php',
        'WordLevelDiff' => __DIR__ . '/includes/diff/WordLevelDiff.php',
        'WrapOldPasswords' => __DIR__ . '/maintenance/wrapOldPasswords.php',
        'XCFHandler' => __DIR__ . '/includes/media/XCFHandler.php',
index 43234c6..43bfd8d 100644 (file)
@@ -1585,7 +1585,8 @@ entitled to be in.
 $user: user to promote.
 &$promote: groups that will be added.
 
-'GetBlockedStatus': after loading blocking status of an user from the database
+'GetBlockedStatus': DEPRECATED since 1.34 - use GetUserBlock instead. After
+loading blocking status of a user from the database
 &$user: user (object) being checked
 
 'GetCacheVaryCookies': Get cookies that should vary cache options.
index f6ac342..c9bed29 100644 (file)
@@ -4888,6 +4888,7 @@ $wgDefaultUserOptions = [
        'wllimit' => 250,
        'useeditwarning' => 1,
        'prefershttps' => 1,
+       'requireemail' => 0,
 ];
 
 /**
@@ -4957,6 +4958,15 @@ $wgSessionProviders = [
        ],
 ];
 
+/**
+ * Temporary feature flag that controls whether users will see a checkbox allowing them to
+ * require providing email during password resets.
+ *
+ * @deprecated This feature is under development, don't assume this flag's existence or function
+ *     outside of MediaWiki.
+ */
+$wgAllowRequiringEmailForResets = false;
+
 /** @} */ # end user accounts }
 
 /************************************************************************//**
index 564c8f4..634e7af 100644 (file)
@@ -473,6 +473,7 @@ class MovePage {
 
                        $mp = new MovePage( $oldSubpage, $newSubpage );
                        $method = $checkPermissions ? 'moveIfAllowed' : 'move';
+                       /** @var Status $status */
                        $status = $mp->$method( $user, $reason, $createRedirect, $changeTags );
                        if ( $status->isOK() ) {
                                $status->setResult( true, $newSubpage->getPrefixedText() );
@@ -508,7 +509,7 @@ class MovePage {
 
                Hooks::run( 'TitleMoveStarting', [ $this->oldTitle, $this->newTitle, $user ] );
 
-               $pageid = $this->oldTitle->getArticleID( Title::GAID_FOR_UPDATE );
+               $pageid = $this->oldTitle->getArticleID( Title::READ_LATEST );
                $protected = $this->oldTitle->isProtected();
 
                // Do the actual move; if this fails, it will throw an MWException(!)
index 292d6ba..828f647 100644 (file)
@@ -1005,7 +1005,7 @@ class Revision implements IDBAccessObject {
 
                $comment = CommentStoreComment::newUnsavedComment( $summary, null );
 
-               $title = Title::newFromID( $pageId, Title::GAID_FOR_UPDATE );
+               $title = Title::newFromID( $pageId, Title::READ_LATEST );
                if ( $title === null ) {
                        return null;
                }
index 73f622a..735a212 100644 (file)
@@ -326,10 +326,10 @@ class RevisionStore
 
                $canUseTitleNewFromId = ( $pageId !== null && $pageId > 0 && $this->dbDomain === false );
                list( $dbMode, $dbOptions ) = DBAccessObjectUtils::getDBOptions( $queryFlags );
-               $titleFlags = ( $dbMode == DB_MASTER ? Title::GAID_FOR_UPDATE : 0 );
 
                // Loading by ID is best, but Title::newFromID does not support that for foreign IDs.
                if ( $canUseTitleNewFromId ) {
+                       $titleFlags = ( $dbMode == DB_MASTER ? Title::READ_LATEST : 0 );
                        // TODO: better foreign title handling (introduce TitleFactory)
                        $title = Title::newFromID( $pageId, $titleFlags );
                        if ( $title ) {
index 39f0c81..518531a 100644 (file)
@@ -808,22 +808,17 @@ if ( !defined( 'MW_NO_SESSION' ) && !$wgCommandLineMode ) {
        // Initialize the session
        try {
                $session = MediaWiki\Session\SessionManager::getGlobalSession();
-       } catch ( OverflowException $ex ) {
-               if ( isset( $ex->sessionInfos ) && count( $ex->sessionInfos ) >= 2 ) {
-                       // The exception is because the request had multiple possible
-                       // sessions tied for top priority. Report this to the user.
-                       $list = [];
-                       foreach ( $ex->sessionInfos as $info ) {
-                               $list[] = $info->getProvider()->describe( $wgContLang );
-                       }
-                       $list = $wgContLang->listToText( $list );
-                       throw new HttpError( 400,
-                               Message::newFromKey( 'sessionmanager-tie', $list )->inLanguage( $wgContLang )->plain()
-                       );
+       } catch ( MediaWiki\Session\SessionOverflowException $ex ) {
+               // The exception is because the request had multiple possible
+               // sessions tied for top priority. Report this to the user.
+               $list = [];
+               foreach ( $ex->getSessionInfos() as $info ) {
+                       $list[] = $info->getProvider()->describe( $wgContLang );
                }
-
-               // Not the one we want, rethrow
-               throw $ex;
+               $list = $wgContLang->listToText( $list );
+               throw new HttpError( 400,
+                       Message::newFromKey( 'sessionmanager-tie', $list )->inLanguage( $wgContLang )->plain()
+               );
        }
 
        if ( $session->isPersistent() ) {
index d2bbe7b..7e9f56d 100644 (file)
@@ -93,7 +93,7 @@ class ApiSetNotificationTimestamp extends ApiBase {
                        $titles = $pageSet->getGoodTitles();
                        $title = reset( $titles );
                        if ( $title ) {
-                               $revid = $title->getNextRevisionID( $params['newerthanrevid'], Title::GAID_FOR_UPDATE );
+                               $revid = $title->getNextRevisionID( $params['newerthanrevid'], Title::READ_LATEST );
                                if ( $revid ) {
                                        $timestamp = $dbw->timestamp(
                                                MediaWikiServices::getInstance()->getRevisionStore()->getTimestampFromId( $title, $revid )
index dc9c516..09d9c46 100644 (file)
        "apierror-cantoverwrite-sharedfile": "الملف الهدف موجود في مستودع مشترك وليست لديك صلاحية لتجاوزه.",
        "apierror-cantsend": "لم تقم بتسجيل الدخول أو ليس لديك عنوان بريد إلكتروني مؤكد أو غير مسموح لك بإرسال بريد إلكتروني إلى مستخدمين آخرين; لذلك لا يمكنك إرسال بريد إلكتروني.",
        "apierror-cantundelete": "تعذر الاسترجاع: قد لا تكون المراجعات المطلوبة موجودة، أو ربما تم الاسترجاع بالفعل.",
+       "apierror-cantview-deleted-description": "ليست لديك صلايبة لعرض أوصاف الملفات المحذوفة.",
+       "apierror-cantview-deleted-metadata": "ليست لديك صلايبة لعرض البيانات الوصفية للملفات المحذوفة.",
        "apierror-changeauth-norequest": "فشل في إنشاء طلب التغيير.",
        "apierror-chunk-too-small": "الحد الأدنى لحجم القطعة هو $1 {{PLURAL:$1|بايت}} للقطع غير النهائية.",
        "apierror-cidrtoobroad": "لا يُقبَل مدى $1 CIDR أكبر من /$2.",
index 628edfa..7c5d2b5 100644 (file)
        "apierror-cantoverwrite-sharedfile": "Le fichier cible existe dans un dépôt partagé et vous n’avez pas le droit de l’écraser.",
        "apierror-cantsend": "Vous n’êtes pas connecté, vous n’avez pas d’adresse de courriel confirmée, ou vous n’êtes pas autorisé à envoyer des courriels aux autres utilisateurs, donc vous ne pouvez envoyer de courriel.",
        "apierror-cantundelete": "Impossible d’annuler : les révisions demandées peuvent ne plus exister, ou avoir déjà été annulées.",
+       "apierror-cantview-deleted-description": "Vous n’avez pas le droit d’afficher les descriptions des fichiers supprimés.",
+       "apierror-cantview-deleted-metadata": "Vous n’avez pas le droit d’afficher les métadonnées des fichiers supprimés.",
        "apierror-changeauth-norequest": "Échec à la création de la requête de modification.",
        "apierror-chunk-too-small": "La taille minimale d’un segment est de $1 {{PLURAL:$1|octet|octets}} pour les segments hors le dernier.",
        "apierror-cidrtoobroad": "Les plages CIDR $1 plus large que /$2 ne sont pas acceptées.",
index e71a9dc..d8ff539 100644 (file)
@@ -17,7 +17,8 @@
                        "InternerowyGołąb",
                        "CiaPan",
                        "Vlad5250",
-                       "Railfail536"
+                       "Railfail536",
+                       "Rail"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Dokumentacja]]\n* [[mw:Special:MyLanguage/API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lista dyskusyjna]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Ogłoszenia dotyczące API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Błędy i propozycje]\n</div>\n<strong>Stan:</strong> Wszystkie funkcje opisane na tej stronie powinny działać, ale API nadal jest aktywnie rozwijane i mogą się zmienić w dowolnym czasie. Subskrybuj [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ listę dyskusyjną mediawiki-api-announce], aby móc na bieżąco dowiadywać się o aktualizacjach.\n\n<strong>Błędne żądania:</strong> Gdy zostanie wysłane błędne żądanie do API, zostanie wysłany w odpowiedzi nagłówek HTTP z kluczem \"MediaWiki-API-Error\" i zarówno jego wartość jak i wartość kodu błędu wysłanego w odpowiedzi będą miały taką samą wartość. Aby uzyskać więcej informacji, zobacz [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Błędy i ostrzeżenia]].\n\n<strong>Testowanie:</strong> Aby łatwo testować żądania API, zobacz [[Special:ApiSandbox]].",
        "apierror-cantimport": "Nie masz uprawnień do importowania stron.",
        "apierror-cantsend": "Nie jesteś zalogowany, nie masz potwierdzonego adresu e-mail, albo nie masz prawa wysyłać e-maili do innych użytkowników, więc nie możesz wysłać wiadomości e-mail.",
        "apierror-cantundelete": "Nie można przywrócić: dana wersja nie istnieje albo została już przywrócona.",
+       "apierror-cantview-deleted-description": "Nie masz uprawnień do podglądu opisów usuniętych plików.",
+       "apierror-cantview-deleted-metadata": "Nie masz uprawnień do podglądu metadanych usuniętych plików.",
        "apierror-exceptioncaught": "[$1] Stwierdzono wyjątek: $2",
        "apierror-filedoesnotexist": "Plik nie istnieje.",
        "apierror-import-unknownerror": "Nieznany błąd podczas importowania: $1.",
index 14a7717..7ee3751 100644 (file)
        "apierror-cantoverwrite-sharedfile": "目標檔案存在於分享儲存庫上,因此您沒有權限來覆蓋掉。",
        "apierror-cantsend": "您尚未登入,您沒有已確認的電子郵件地址,或是您未被允許發送電子郵件給其他人,因此您不能發送電子郵件。",
        "apierror-cantundelete": "無法取消刪除:請求的修訂可能不存在,或是可能已被取消刪除。",
+       "apierror-cantview-deleted-description": "您沒有權限來檢視被刪除檔案的描述內容。",
+       "apierror-cantview-deleted-metadata": "您沒有權限來檢視被刪除檔案的詮釋資料。",
        "apierror-changeauth-norequest": "建立更改請求失敗。",
        "apierror-chunk-too-small": "對於非最終塊,最小塊的大小為 $1 {{PLURAL:$1|位元組|位元組}}。",
        "apierror-cidrtoobroad": "不能接受超出 /$2 的 $1 CIDR 範圍。",
index 8018117..b2f2452 100644 (file)
@@ -89,6 +89,7 @@ class LinkCache {
         *
         * @param bool|null $update
         * @return bool
+        * @deprecated Since 1.34
         */
        public function forUpdate( $update = null ) {
                return wfSetVar( $this->mForUpdate, $update );
index 88a7042..a79325a 100644 (file)
@@ -27,18 +27,20 @@ use Wikimedia\Rdbms\DBQueryError;
  * This will work on any MediaWiki installation.
  */
 class LCStoreDB implements LCStore {
-       /** @var string */
-       private $currentLang;
-       /** @var bool */
-       private $writesDone = false;
+       /** @var string Language code */
+       private $code;
+       /** @var array Server configuration map */
+       private $server;
+
+       /** @var array Rows buffered for insertion */
+       private $batch = [];
+
        /** @var IDatabase|null */
        private $dbw;
-       /** @var array */
-       private $batch = [];
-       /** @var bool */
+       /** @var bool Whether a batch of writes were recently written */
+       private $writesDone = false;
+       /** @var bool Whether the DB is read-only or otherwise unavailable for writes */
        private $readOnly = false;
-       /** @var array Server configuration map */
-       private $server;
 
        public function __construct( $params ) {
                $this->server = $params['server'] ?? [];
@@ -74,14 +76,14 @@ class LCStoreDB implements LCStore {
                $dbw = $this->getWriteConnection();
                $this->readOnly = $dbw->isReadOnly();
 
-               $this->currentLang = $code;
+               $this->code = $code;
                $this->batch = [];
        }
 
        public function finishWrite() {
                if ( $this->readOnly ) {
                        return;
-               } elseif ( is_null( $this->currentLang ) ) {
+               } elseif ( is_null( $this->code ) ) {
                        throw new MWException( __CLASS__ . ': must call startWrite() before finishWrite()' );
                }
 
@@ -91,7 +93,7 @@ class LCStoreDB implements LCStore {
                        $dbw = $this->getWriteConnection();
                        $dbw->startAtomic( __METHOD__ );
                        try {
-                               $dbw->delete( 'l10n_cache', [ 'lc_lang' => $this->currentLang ], __METHOD__ );
+                               $dbw->delete( 'l10n_cache', [ 'lc_lang' => $this->code ], __METHOD__ );
                                foreach ( array_chunk( $this->batch, 500 ) as $rows ) {
                                        $dbw->insert( 'l10n_cache', $rows, __METHOD__ );
                                }
@@ -108,21 +110,21 @@ class LCStoreDB implements LCStore {
                        $trxProfiler->setSilenced( $oldSilenced );
                }
 
-               $this->currentLang = null;
+               $this->code = null;
                $this->batch = [];
        }
 
        public function set( $key, $value ) {
                if ( $this->readOnly ) {
                        return;
-               } elseif ( is_null( $this->currentLang ) ) {
+               } elseif ( is_null( $this->code ) ) {
                        throw new MWException( __CLASS__ . ': must call startWrite() before set()' );
                }
 
                $dbw = $this->getWriteConnection();
 
                $this->batch[] = [
-                       'lc_lang' => $this->currentLang,
+                       'lc_lang' => $this->code,
                        'lc_key' => $key,
                        'lc_value' => $dbw->encodeBlob( serialize( $value ) )
                ];
index 74e236f..8345ee6 100644 (file)
@@ -125,7 +125,7 @@ class LinksUpdate extends DataUpdate {
 
                if ( !$this->mId ) {
                        // NOTE: subclasses may initialize mId before calling this constructor!
-                       $this->mId = $title->getArticleID( Title::GAID_FOR_UPDATE );
+                       $this->mId = $title->getArticleID( Title::READ_LATEST );
                }
 
                if ( !$this->mId ) {
index 4db351b..264eabc 100644 (file)
@@ -26,6 +26,7 @@ use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\DBConnRef;
 use Wikimedia\Rdbms\MaintainableDBConnRef;
 use Wikimedia\Rdbms\DatabaseDomain;
+use Wikimedia\Rdbms\DBUnexpectedError;
 
 /**
  * DB accessible external objects.
@@ -113,7 +114,11 @@ class ExternalStoreDB extends ExternalStoreMedium {
         */
        public function store( $location, $data ) {
                $dbw = $this->getMaster( $location );
-               $dbw->insert( $this->getTable( $dbw ), [ 'blob_text' => $data ], __METHOD__ );
+               $dbw->insert(
+                       $this->getTable( $dbw, $location ),
+                       [ 'blob_text' => $data ],
+                       __METHOD__
+               );
                $id = $dbw->insertId();
                if ( !$id ) {
                        throw new MWException( __METHOD__ . ': no insert ID' );
@@ -149,10 +154,11 @@ class ExternalStoreDB extends ExternalStoreMedium {
        /**
         * Get a replica DB connection for the specified cluster
         *
+        * @since 1.34
         * @param string $cluster Cluster name
         * @return DBConnRef
         */
-       public function getSlave( $cluster ) {
+       public function getReplica( $cluster ) {
                $lb = $this->getLoadBalancer( $cluster );
 
                return $lb->getConnectionRef(
@@ -163,6 +169,17 @@ class ExternalStoreDB extends ExternalStoreMedium {
                );
        }
 
+       /**
+        * Get a replica DB connection for the specified cluster
+        *
+        * @param string $cluster Cluster name
+        * @return DBConnRef
+        * @deprecated since 1.34
+        */
+       public function getSlave( $cluster ) {
+               return $this->getReplica( $cluster );
+       }
+
        /**
         * Get a master database connection for the specified cluster
         *
@@ -211,15 +228,55 @@ class ExternalStoreDB extends ExternalStoreMedium {
         * Get the 'blobs' table name for this database
         *
         * @param IDatabase $db
+        * @param string|null $cluster Cluster name
         * @return string Table name ('blobs' by default)
         */
-       public function getTable( $db ) {
-               $table = $db->getLBInfo( 'blobs table' );
-               if ( is_null( $table ) ) {
-                       $table = 'blobs';
+       public function getTable( $db, $cluster = null ) {
+               if ( $cluster !== null ) {
+                       $lb = $this->getLoadBalancer( $cluster );
+                       $info = $lb->getServerInfo( $lb->getWriterIndex() );
+                       if ( isset( $info['blobs table'] ) ) {
+                               return $info['blobs table'];
+                       }
                }
 
-               return $table;
+               return $db->getLBInfo( 'blobs table' ) ?? 'blobs'; // b/c
+       }
+
+       /**
+        * Create the appropriate blobs table on this cluster
+        *
+        * @see getTable()
+        * @since 1.34
+        * @param string $cluster
+        */
+       public function initializeTable( $cluster ) {
+               global $IP;
+
+               static $supportedTypes = [ 'mysql', 'sqlite' ];
+
+               $dbw = $this->getMaster( $cluster );
+               if ( !in_array( $dbw->getType(), $supportedTypes, true ) ) {
+                       throw new DBUnexpectedError( $dbw, "RDBMS type '{$dbw->getType()}' not supported." );
+               }
+
+               $sqlFilePath = "$IP/maintenance/storage/blobs.sql";
+               $sql = file_get_contents( $sqlFilePath );
+               if ( $sql === false ) {
+                       throw new RuntimeException( "Failed to read '$sqlFilePath'." );
+               }
+
+               $rawTable = $this->getTable( $dbw, $cluster ); // e.g. "blobs_cluster23"
+               $encTable = $dbw->tableName( $rawTable );
+               $dbw->query(
+                       str_replace(
+                               [ '/*$wgDBprefix*/blobs', '/*_*/blobs' ],
+                               [ $encTable, $encTable ],
+                               $sql
+                       ),
+                       __METHOD__,
+                       $dbw::QUERY_IGNORE_DBO_TRX
+               );
        }
 
        /**
@@ -251,15 +308,23 @@ class ExternalStoreDB extends ExternalStoreMedium {
 
                $this->logger->debug( "ExternalStoreDB::fetchBlob cache miss on $cacheID" );
 
-               $dbr = $this->getSlave( $cluster );
-               $ret = $dbr->selectField( $this->getTable( $dbr ),
-                       'blob_text', [ 'blob_id' => $id ], __METHOD__ );
+               $dbr = $this->getReplica( $cluster );
+               $ret = $dbr->selectField(
+                       $this->getTable( $dbr, $cluster ),
+                       'blob_text',
+                       [ 'blob_id' => $id ],
+                       __METHOD__
+               );
                if ( $ret === false ) {
                        $this->logger->info( "ExternalStoreDB::fetchBlob master fallback on $cacheID" );
                        // Try the master
                        $dbw = $this->getMaster( $cluster );
-                       $ret = $dbw->selectField( $this->getTable( $dbw ),
-                               'blob_text', [ 'blob_id' => $id ], __METHOD__ );
+                       $ret = $dbw->selectField(
+                               $this->getTable( $dbw, $cluster ),
+                               'blob_text',
+                               [ 'blob_id' => $id ],
+                               __METHOD__
+                       );
                        if ( $ret === false ) {
                                $this->logger->error( "ExternalStoreDB::fetchBlob master failed to find $cacheID" );
                        }
@@ -283,9 +348,9 @@ class ExternalStoreDB extends ExternalStoreMedium {
         *   Unlocated ids are not represented
         */
        private function batchFetchBlobs( $cluster, array $ids ) {
-               $dbr = $this->getSlave( $cluster );
+               $dbr = $this->getReplica( $cluster );
                $res = $dbr->select(
-                       $this->getTable( $dbr ),
+                       $this->getTable( $dbr, $cluster ),
                        [ 'blob_id', 'blob_text' ],
                        [ 'blob_id' => array_keys( $ids ) ],
                        __METHOD__
@@ -302,7 +367,8 @@ class ExternalStoreDB extends ExternalStoreMedium {
                        );
                        // Try the master
                        $dbw = $this->getMaster( $cluster );
-                       $res = $dbw->select( $this->getTable( $dbr ),
+                       $res = $dbw->select(
+                               $this->getTable( $dbr, $cluster ),
                                [ 'blob_id', 'blob_text' ],
                                [ 'blob_id' => array_keys( $ids ) ],
                                __METHOD__ );
index eae79b0..e5ebb42 100644 (file)
        "config-restart": "Si, reinitia lo",
        "config-welcome": "=== Verificationes del ambiente ===\nVerificationes de base essera ora exequite pro determinar si iste ambiente es apte pro le installation de MediaWiki.\nNon oblida de includer iste information si tu cerca adjuta pro completar le installation.",
        "config-welcome-section-copyright": "=== Copyright and Terms ===\n\n$1\n\nIste programma es software libere; vos pote redistribuer lo e/o modificar lo sub le conditiones del Licentia Public General de GNU publicate per le Free Software Foundation; version 2 del Licentia, o (a vostre option) qualcunque version posterior.\n\nIste programma es distribuite in le sperantia que illo sia utile, ma '''sin garantia''', sin mesmo le implicite garantia de '''commercialisation''' o '''aptitude pro un proposito particular'''.\nVide le Licentia Public General de GNU pro plus detalios.\n\nVos deberea haber recipite [$2 un exemplar del Licentia Public General de GNU] con iste programma; si non, scribe al Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, o [https://www.gnu.org/copyleft/gpl.html lege lo in linea].",
-       "config-sidebar": "* [https://www.mediawiki.org Pagina principal de MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guida pro usatores]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Guida pro administratores]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]\n----\n* <doclink href=Readme>Lege me</doclink>\n* <doclink href=ReleaseNotes>Notas de iste version</doclink>\n* <doclink href=Copying>Conditiones de copia</doclink>\n* <doclink href=UpgradeDoc>Actualisation</doclink>",
+       "config-sidebar": "* [https://www.mediawiki.org Pagina principal de MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guida pro usatores]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Guida pro administratores]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]",
+       "config-sidebar-readme": "Lege me",
+       "config-sidebar-relnotes": "Notas de iste version",
+       "config-sidebar-license": "Conditiones de copia",
+       "config-sidebar-upgrade": "Actualisation",
        "config-env-good": "Le ambiente ha essite verificate.\nTu pote installar MediaWiki.",
        "config-env-bad": "Le ambiente ha essite verificate.\nTu non pote installar MediaWiki.",
        "config-env-php": "PHP $1 es installate.",
@@ -79,7 +83,7 @@
        "config-uploads-not-safe": "'''Aviso:''' Le directorio predefinite pro files incargate <code>$1</code> es vulnerabile al execution arbitrari de scripts.\nBen que MediaWiki verifica tote le files incargate contra le menacias de securitate, il es altemente recommendate [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security remediar iste vulnerabilitate de securitate] ante de activar le incargamento de files.",
        "config-no-cli-uploads-check": "'''Attention:''' Le directorio predefinite pro files incargate (<code>$1</code>) non es verificate contra le vulnerabilitate\nal execution arbitrari de scripts durante le installation de CLI.",
        "config-brokenlibxml": "Vostre systema ha un combination de versiones de PHP e libxml2 que es defectuose e pote causar corruption celate de datos in MediaWiki e altere applicationes web.\nActualisa a libxml2 2.7.3 o plus recente ([https://bugs.php.net/bug.php?id=45996 problema reportate presso PHP]).\nInstallation abortate.",
-       "config-suhosin-max-value-length": "Suhosin es installate e limita parametro <code>length</code> de GET a $1 bytes.\nLe componente ResourceLoader de MediaWiki va contornar iste limite, ma isto prejudicara le rendimento.\nSi possibile, tu deberea mitter <code>suhosin.get.max_value_length</code> a 1024 o superior in <code>php.ini</code>, e mitter <code>$wgResourceLoaderMaxQueryLength</code> al mesme valor in <code>LocalSettings.php</code>.",
+       "config-suhosin-max-value-length": "Suhosin es installate e limita parametro <code>length</code> de GET a $1 bytes.\nMediaWiki require que <code>suhosin.get.max_value_length</code> sia al minus $2. Disactiva iste parametro, o augmenta iste valor a $3 in <code>php.ini</code>.",
        "config-using-32bit": "<strong>Attention:</strong> tu systema pare operar con integres de 32 bits. Isto [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit non es recommendate].",
        "config-db-type": "Typo de base de datos:",
        "config-db-host": "Servitor de base de datos:",
index 5da1914..511b0da 100644 (file)
        "config-uploads-not-safe": "<strong>警告:</strong> アップロードの既定ディレクトリ <code>$1</code> に、任意のスクリプト実行に関する脆弱性があります。\nMediaWiki はアップロードされたファイルのセキュリティ上の脅威を確認しますが、アップロードを有効化する前に、[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security このセキュリティ上の脆弱性を解決する]ことを強く推奨します。",
        "config-no-cli-uploads-check": "<strong>警告:</strong> アップロード用のデフォルトディレクトリ (<code>$1</code>) が、CLIでのインストール中に任意のスクリプト実行の脆弱性チェックを受けていません。",
        "config-brokenlibxml": "このシステムで使われているPHPとlibxml2のバージョンのこの組み合わせにはバグがあります。具体的には、MediaWikiやその他のウェブアプリケーションでhiddenデータが破損する可能性があります。\nlibxml2を2.7.3以降のバージョンにアップグレードしてください([https://bugs.php.net/bug.php?id=45996 PHPでのバグ情報])。\nインストールを終了します。",
-       "config-suhosin-max-value-length": "Suhosin がインストールされており、GET パラメーターの <code>length</code> を $1 バイトに制限しています。\nMediaWiki の ResourceLoader コンポーネントはこの制限を回避しますが、パフォーマンスは低下します。\n可能な限り、<code>php.ini</code> で <code>suhosin.get.max_value_length</code> を 1024 以上に設定し、同じ値を <code>LocalSettings.php</code> 内で <code>$wgResourceLoaderMaxQueryLength</code> に設定してください。",
+       "config-suhosin-max-value-length": "Suhosin がインストールされており、GET パラメーターの <code>length</code> を $1 バイトに制限しています。(訳注:\nMediaWiki の ResourceLoader コンポーネントはこの制限を回避しますが、パフォーマンスは低下します。)\n可能な限り、 <code>suhosin.get.max_value_length</code> を $2 以上に設定します。これを無効に変更するか、<code>php.ini</code> で $3 に増加してください。",
        "config-using-32bit": "<strong>警告:</strong>システムが32ビットで動作しているようです。 これは[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:32-bit 非推奨]です。",
        "config-db-type": "データベースの種類:",
        "config-db-host": "データベースのホスト:",
index fc66bdb..f3f211e 100644 (file)
@@ -24,7 +24,8 @@
                        "Sethakill",
                        "Peter Bowman",
                        "Ankam",
-                       "Railfail536"
+                       "Railfail536",
+                       "Rail"
                ]
        },
        "config-desc": "Instalator MediaWiki",
index b4046a6..33b05b8 100644 (file)
@@ -276,8 +276,8 @@ class RefreshLinksJob extends Job {
                $title = $page->getTitle();
                // Get the latest ID since acquirePageLock() in runForTitle() flushed the transaction.
                // This is used to detect edits/moves after loadPageData() but before the scope lock.
-               // The works around the chicken/egg problem of determining the scope lock key name.
-               $latest = $title->getLatestRevID( Title::GAID_FOR_UPDATE );
+               // The works around the chicken/egg problem of determining the scope lock key name
+               $latest = $title->getLatestRevID( Title::READ_LATEST );
 
                $triggeringRevisionId = $this->params['triggeringRevisionId'] ?? null;
                if ( $triggeringRevisionId && $triggeringRevisionId !== $latest ) {
index 5534cbd..9ed7ae3 100644 (file)
@@ -556,9 +556,7 @@ class FSFileBackend extends FileBackendStore {
                $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
                $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
                AtEase::suppressWarnings();
-               if ( is_dir( $dir ) ) {
-                       rmdir( $dir ); // remove directory if empty
-               }
+               rmdir( $dir ); // remove directory if empty
                AtEase::restoreWarnings();
 
                return $status;
index f2c07e8..5caf250 100644 (file)
@@ -1587,7 +1587,7 @@ abstract class FileBackendStore extends FileBackend {
                                // Validate and sanitize the relative path (backend-specific)
                                $relPath = $this->resolveContainerPath( $shortCont, $relPath );
                                if ( $relPath !== null ) {
-                                       // Prepend any wiki ID prefix to the container name
+                                       // Prepend any domain ID prefix to the container name
                                        $container = $this->fullContainerName( $shortCont );
                                        if ( self::isValidContainerName( $container ) ) {
                                                // Validate and sanitize the container name (backend-specific)
@@ -1722,7 +1722,7 @@ abstract class FileBackendStore extends FileBackend {
        }
 
        /**
-        * Get the full container name, including the wiki ID prefix
+        * Get the full container name, including the domain ID prefix
         *
         * @param string $container
         * @return string
index c366a0f..8697f9f 100644 (file)
@@ -34,8 +34,8 @@ abstract class FileBackendStoreOpHandle {
        public $backend;
        /** @var array */
        public $resourcesToClose = [];
-
-       public $call; // string; name that identifies the function called
+       /** @var callable name that identifies the function called */
+       public $call;
 
        /**
         * Close all open file handles
index c167f3a..bad75da 100644 (file)
@@ -726,7 +726,7 @@ class WikiPage implements Page, IDBAccessObject {
                // Try using the replica DB first, then try the master
                $rev = $this->mTitle->getFirstRevision();
                if ( !$rev ) {
-                       $rev = $this->mTitle->getFirstRevision( Title::GAID_FOR_UPDATE );
+                       $rev = $this->mTitle->getFirstRevision( Title::READ_LATEST );
                }
                return $rev;
        }
index 8a82add..66c2bc3 100644 (file)
@@ -84,6 +84,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
         * @since 1.34
         */
        public static $constructorOptions = [
+               'AllowRequiringEmailForResets',
                'AllowUserCss',
                'AllowUserCssPrefs',
                'AllowUserJs',
@@ -620,6 +621,16 @@ class DefaultPreferencesFactory implements PreferencesFactory {
                                }
                        }
 
+                       if ( $this->options->get( 'AllowRequiringEmailForResets' ) ) {
+                               $defaultPreferences['requireemail'] = [
+                                       'type' => 'toggle',
+                                       'label-message' => 'tog-requireemail',
+                                       'help-message' => 'prefs-help-requireemail',
+                                       'section' => 'personal/email',
+                                       'disabled' => $disableEmailPrefs,
+                               ];
+                       }
+
                        if ( $this->options->get( 'EnableUserEmail' ) && $user->isAllowed( 'sendemail' ) ) {
                                $defaultPreferences['disablemail'] = [
                                        'id' => 'wpAllowEmail',
index 693afcf..4a23eae 100644 (file)
@@ -1273,8 +1273,7 @@ MESSAGE;
        /**
         * Returns JS code which, when called, will register a given list of messages.
         *
-        * @param mixed $messages Either an associative array mapping message key to value, or a
-        *   JSON-encoded message blob containing the same data, wrapped in an XmlJsCode object.
+        * @param mixed $messages Associative array mapping message key to value.
         * @return string JavaScript code
         */
        public static function makeMessageSetScript( $messages ) {
index 09cdf72..a3380ff 100644 (file)
@@ -505,11 +505,10 @@ final class SessionManager implements SessionManagerInterface {
                }
 
                if ( count( $retInfos ) > 1 ) {
-                       $ex = new \OverflowException(
+                       throw new SessionOverflowException(
+                               $retInfos,
                                'Multiple sessions for this request tied for top priority: ' . implode( ', ', $retInfos )
                        );
-                       $ex->sessionInfos = $retInfos;
-                       throw $ex;
                }
 
                return $retInfos ? $retInfos[0] : null;
diff --git a/includes/session/SessionOverflowException.php b/includes/session/SessionOverflowException.php
new file mode 100644 (file)
index 0000000..2a5ed2b
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+namespace MediaWiki\Session;
+
+/**
+ * OverflowException specific to the SessionManager, used when the request had multiple possible
+ * sessions tied for top priority.
+ *
+ * @since 1.34
+ */
+class SessionOverflowException extends \OverflowException {
+       /** @var SessionInfo[] */
+       private $sessionInfos;
+
+       /**
+        * @param SessionInfo[] $sessionInfos Must have at least two elements
+        * @param string $msg
+        * @throws \InvalidArgumentException If $sessionInfos has less than 2 elements
+        */
+       function __construct( array $sessionInfos, $msg ) {
+               if ( count( $sessionInfos ) < 2 ) {
+                       throw new \InvalidArgumentException( 'Expected at least two SessionInfo objects.' );
+               }
+               parent::__construct( $msg );
+               $this->sessionInfos = $sessionInfos;
+       }
+
+       /**
+        * @return SessionInfo[]
+        */
+       public function getSessionInfos() : array {
+               return $this->sessionInfos;
+       }
+}
index ce80c1a..e5a28d9 100644 (file)
@@ -95,9 +95,8 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
 
        /**
         * Load basic request parameters for this Special page.
-        * @param string $subPage
         */
-       private function loadRequestParameters( $subPage ) {
+       private function loadRequestParameters() {
                if ( $this->mLoadedRequest ) {
                        return;
                }
@@ -105,7 +104,6 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
                $request = $this->getRequest();
 
                $this->mPosted = $request->wasPosted();
-               $this->mIsReturn = $subPage === 'return';
                $this->mAction = $request->getVal( 'action' );
                $this->mFromHTTP = $request->getBool( 'fromhttp', false )
                        || $request->getBool( 'wpFromhttp', false );
@@ -124,7 +122,7 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
        protected function load( $subPage ) {
                global $wgSecureLogin;
 
-               $this->loadRequestParameters( $subPage );
+               $this->loadRequestParameters();
                if ( $this->mLoaded ) {
                        return;
                }
@@ -203,7 +201,7 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
 
        protected function beforeExecute( $subPage ) {
                // finish initializing the class before processing the request - T135924
-               $this->loadRequestParameters( $subPage );
+               $this->loadRequestParameters();
                return parent::beforeExecute( $subPage );
        }
 
index 6cc6e4e..b7eb3c0 100644 (file)
@@ -77,40 +77,40 @@ abstract class QueryPage extends SpecialPage {
                if ( $qp === null ) {
                        // QueryPage subclass, Special page name
                        $qp = [
-                               [ AncientPagesPage::class, 'Ancientpages' ],
-                               [ BrokenRedirectsPage::class, 'BrokenRedirects' ],
-                               [ DeadendPagesPage::class, 'Deadendpages' ],
-                               [ DoubleRedirectsPage::class, 'DoubleRedirects' ],
-                               [ FileDuplicateSearchPage::class, 'FileDuplicateSearch' ],
-                               [ ListDuplicatedFilesPage::class, 'ListDuplicatedFiles' ],
-                               [ LinkSearchPage::class, 'LinkSearch' ],
-                               [ ListredirectsPage::class, 'Listredirects' ],
-                               [ LonelyPagesPage::class, 'Lonelypages' ],
-                               [ LongPagesPage::class, 'Longpages' ],
-                               [ MediaStatisticsPage::class, 'MediaStatistics' ],
-                               [ MIMEsearchPage::class, 'MIMEsearch' ],
-                               [ MostcategoriesPage::class, 'Mostcategories' ],
+                               [ SpecialAncientPages::class, 'Ancientpages' ],
+                               [ SpecialBrokenRedirects::class, 'BrokenRedirects' ],
+                               [ SpecialDeadendPages::class, 'Deadendpages' ],
+                               [ SpecialDoubleRedirects::class, 'DoubleRedirects' ],
+                               [ SpecialFileDuplicateSearch::class, 'FileDuplicateSearch' ],
+                               [ SpecialListDuplicatedFiles::class, 'ListDuplicatedFiles' ],
+                               [ SpecialLinkSearch::class, 'LinkSearch' ],
+                               [ SpecialListRedirects::class, 'Listredirects' ],
+                               [ SpecialLonelyPages::class, 'Lonelypages' ],
+                               [ SpecialLongPages::class, 'Longpages' ],
+                               [ SpecialMediaStatistics::class, 'MediaStatistics' ],
+                               [ SpecialMIMESearch::class, 'MIMEsearch' ],
+                               [ SpecialMostCategories::class, 'Mostcategories' ],
                                [ MostimagesPage::class, 'Mostimages' ],
-                               [ MostinterwikisPage::class, 'Mostinterwikis' ],
-                               [ MostlinkedCategoriesPage::class, 'Mostlinkedcategories' ],
-                               [ MostlinkedTemplatesPage::class, 'Mostlinkedtemplates' ],
-                               [ MostlinkedPage::class, 'Mostlinked' ],
-                               [ MostrevisionsPage::class, 'Mostrevisions' ],
-                               [ FewestrevisionsPage::class, 'Fewestrevisions' ],
-                               [ ShortPagesPage::class, 'Shortpages' ],
-                               [ UncategorizedCategoriesPage::class, 'Uncategorizedcategories' ],
-                               [ UncategorizedPagesPage::class, 'Uncategorizedpages' ],
-                               [ UncategorizedImagesPage::class, 'Uncategorizedimages' ],
-                               [ UncategorizedTemplatesPage::class, 'Uncategorizedtemplates' ],
-                               [ UnusedCategoriesPage::class, 'Unusedcategories' ],
-                               [ UnusedimagesPage::class, 'Unusedimages' ],
-                               [ WantedCategoriesPage::class, 'Wantedcategories' ],
+                               [ SpecialMostInterwikis::class, 'Mostinterwikis' ],
+                               [ SpecialMostLinkedCategories::class, 'Mostlinkedcategories' ],
+                               [ SpecialMostLinkedTemplates::class, 'Mostlinkedtemplates' ],
+                               [ SpecialMostLinked::class, 'Mostlinked' ],
+                               [ SpecialMostRevisions::class, 'Mostrevisions' ],
+                               [ SpecialFewestRevisions::class, 'Fewestrevisions' ],
+                               [ SpecialShortPages::class, 'Shortpages' ],
+                               [ SpecialUncategorizedCategories::class, 'Uncategorizedcategories' ],
+                               [ SpecialUncategorizedPages::class, 'Uncategorizedpages' ],
+                               [ SpecialUncategorizedImages::class, 'Uncategorizedimages' ],
+                               [ SpecialUncategorizedTemplates::class, 'Uncategorizedtemplates' ],
+                               [ SpecialUnusedCategories::class, 'Unusedcategories' ],
+                               [ SpecialUnusedImages::class, 'Unusedimages' ],
+                               [ SpecialWantedCategories::class, 'Wantedcategories' ],
                                [ WantedFilesPage::class, 'Wantedfiles' ],
                                [ WantedPagesPage::class, 'Wantedpages' ],
-                               [ WantedTemplatesPage::class, 'Wantedtemplates' ],
-                               [ UnwatchedpagesPage::class, 'Unwatchedpages' ],
-                               [ UnusedtemplatesPage::class, 'Unusedtemplates' ],
-                               [ WithoutInterwikiPage::class, 'Withoutinterwiki' ],
+                               [ SpecialWantedTemplates::class, 'Wantedtemplates' ],
+                               [ SpecialUnwatchedPages::class, 'Unwatchedpages' ],
+                               [ SpecialUnusedTemplates::class, 'Unusedtemplates' ],
+                               [ SpecialWithoutInterwiki::class, 'Withoutinterwiki' ],
                        ];
                        Hooks::run( 'wgQueryPages', [ &$qp ] );
                }
index 2737e35..3f9c491 100644 (file)
@@ -69,35 +69,35 @@ class SpecialPageFactory {
         */
        private static $coreList = [
                // Maintenance Reports
-               'BrokenRedirects' => \BrokenRedirectsPage::class,
-               'Deadendpages' => \DeadendPagesPage::class,
-               'DoubleRedirects' => \DoubleRedirectsPage::class,
-               'Longpages' => \LongPagesPage::class,
-               'Ancientpages' => \AncientPagesPage::class,
-               'Lonelypages' => \LonelyPagesPage::class,
-               'Fewestrevisions' => \FewestrevisionsPage::class,
-               'Withoutinterwiki' => \WithoutInterwikiPage::class,
+               'BrokenRedirects' => \SpecialBrokenRedirects::class,
+               'Deadendpages' => \SpecialDeadendPages::class,
+               'DoubleRedirects' => \SpecialDoubleRedirects::class,
+               'Longpages' => \SpecialLongPages::class,
+               'Ancientpages' => \SpecialAncientPages::class,
+               'Lonelypages' => \SpecialLonelyPages::class,
+               'Fewestrevisions' => \SpecialFewestRevisions::class,
+               'Withoutinterwiki' => \SpecialWithoutInterwiki::class,
                'Protectedpages' => \SpecialProtectedpages::class,
                'Protectedtitles' => \SpecialProtectedtitles::class,
-               'Shortpages' => \ShortPagesPage::class,
-               'Uncategorizedcategories' => \UncategorizedCategoriesPage::class,
-               'Uncategorizedimages' => \UncategorizedImagesPage::class,
-               'Uncategorizedpages' => \UncategorizedPagesPage::class,
-               'Uncategorizedtemplates' => \UncategorizedTemplatesPage::class,
-               'Unusedcategories' => \UnusedCategoriesPage::class,
-               'Unusedimages' => \UnusedimagesPage::class,
-               'Unusedtemplates' => \UnusedtemplatesPage::class,
-               'Unwatchedpages' => \UnwatchedpagesPage::class,
-               'Wantedcategories' => \WantedCategoriesPage::class,
+               'Shortpages' => \SpecialShortPages::class,
+               'Uncategorizedcategories' => \SpecialUncategorizedCategories::class,
+               'Uncategorizedimages' => \SpecialUncategorizedImages::class,
+               'Uncategorizedpages' => \SpecialUncategorizedPages::class,
+               'Uncategorizedtemplates' => \SpecialUncategorizedTemplates::class,
+               'Unusedcategories' => \SpecialUnusedCategories::class,
+               'Unusedimages' => \SpecialUnusedImages::class,
+               'Unusedtemplates' => \SpecialUnusedTemplates::class,
+               'Unwatchedpages' => \SpecialUnwatchedPages::class,
+               'Wantedcategories' => \SpecialWantedCategories::class,
                'Wantedfiles' => \WantedFilesPage::class,
                'Wantedpages' => \WantedPagesPage::class,
-               'Wantedtemplates' => \WantedTemplatesPage::class,
+               'Wantedtemplates' => \SpecialWantedTemplates::class,
 
                // List of pages
                'Allpages' => \SpecialAllPages::class,
                'Prefixindex' => \SpecialPrefixindex::class,
                'Categories' => \SpecialCategories::class,
-               'Listredirects' => \ListredirectsPage::class,
+               'Listredirects' => \SpecialListRedirects::class,
                'PagesWithProp' => \SpecialPagesWithProp::class,
                'TrackingCategories' => \SpecialTrackingCategories::class,
 
@@ -119,7 +119,7 @@ class SpecialPageFactory {
                'ChangePassword' => \SpecialChangePassword::class,
                'BotPasswords' => \SpecialBotPasswords::class,
                'PasswordReset' => \SpecialPasswordReset::class,
-               'DeletedContributions' => \DeletedContributionsPage::class,
+               'DeletedContributions' => \SpecialDeletedContributions::class,
                'Preferences' => \SpecialPreferences::class,
                'ResetTokens' => \SpecialResetTokens::class,
                'Contributions' => \SpecialContributions::class,
@@ -144,12 +144,12 @@ class SpecialPageFactory {
                // Media reports and uploads
                'Listfiles' => \SpecialListFiles::class,
                'Filepath' => \SpecialFilepath::class,
-               'MediaStatistics' => \MediaStatisticsPage::class,
-               'MIMEsearch' => \MIMEsearchPage::class,
-               'FileDuplicateSearch' => \FileDuplicateSearchPage::class,
+               'MediaStatistics' => \SpecialMediaStatistics::class,
+               'MIMEsearch' => \SpecialMIMESearch::class,
+               'FileDuplicateSearch' => \SpecialFileDuplicateSearch::class,
                'Upload' => \SpecialUpload::class,
                'UploadStash' => \SpecialUploadStash::class,
-               'ListDuplicatedFiles' => \ListDuplicatedFilesPage::class,
+               'ListDuplicatedFiles' => \SpecialListDuplicatedFiles::class,
 
                // Data and tools
                'ApiSandbox' => \SpecialApiSandbox::class,
@@ -160,7 +160,7 @@ class SpecialPageFactory {
                'Unlockdb' => \SpecialUnlockdb::class,
 
                // Redirecting special pages
-               'LinkSearch' => \LinkSearchPage::class,
+               'LinkSearch' => \SpecialLinkSearch::class,
                'Randompage' => \RandomPage::class,
                'RandomInCategory' => \SpecialRandomInCategory::class,
                'Randomredirect' => \SpecialRandomredirect::class,
@@ -168,13 +168,13 @@ class SpecialPageFactory {
                'GoToInterwiki' => \SpecialGoToInterwiki::class,
 
                // High use pages
-               'Mostlinkedcategories' => \MostlinkedCategoriesPage::class,
+               'Mostlinkedcategories' => \SpecialMostLinkedCategories::class,
                'Mostimages' => \MostimagesPage::class,
-               'Mostinterwikis' => \MostinterwikisPage::class,
-               'Mostlinked' => \MostlinkedPage::class,
-               'Mostlinkedtemplates' => \MostlinkedTemplatesPage::class,
-               'Mostcategories' => \MostcategoriesPage::class,
-               'Mostrevisions' => \MostrevisionsPage::class,
+               'Mostinterwikis' => \SpecialMostInterwikis::class,
+               'Mostlinked' => \SpecialMostLinked::class,
+               'Mostlinkedtemplates' => \SpecialMostLinkedTemplates::class,
+               'Mostcategories' => \SpecialMostCategories::class,
+               'Mostrevisions' => \SpecialMostRevisions::class,
 
                // Page tools
                'ComparePages' => \SpecialComparePages::class,
@@ -282,8 +282,8 @@ class SpecialPageFactory {
                        }
 
                        if ( $this->options->get( 'EmailAuthentication' ) ) {
-                               $this->list['Confirmemail'] = \EmailConfirmation::class;
-                               $this->list['Invalidateemail'] = \EmailInvalidation::class;
+                               $this->list['Confirmemail'] = \SpecialConfirmEmail::class;
+                               $this->list['Invalidateemail'] = \SpecialEmailInvalidate::class;
                        }
 
                        if ( $this->options->get( 'EnableEmail' ) ) {
diff --git a/includes/specials/SpecialAncientPages.php b/includes/specials/SpecialAncientPages.php
new file mode 100644 (file)
index 0000000..a17c121
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Implements Special:Ancientpages
+ *
+ * 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 SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Implements Special:Ancientpages
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialAncientPages extends QueryPage {
+
+       function __construct( $name = 'Ancientpages' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               $tables = [ 'page', 'revision' ];
+               $conds = [
+                       'page_namespace' =>
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces(),
+                       'page_is_redirect' => 0
+               ];
+               $joinConds = [
+                       'revision' => [
+                               'JOIN', [
+                                       'page_latest = rev_id'
+                               ]
+                       ],
+               ];
+
+               // Allow extensions to modify the query
+               Hooks::run( 'AncientPagesQuery', [ &$tables, &$conds, &$joinConds ] );
+
+               return [
+                       'tables' => $tables,
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'rev_timestamp'
+                       ],
+                       'conds' => $conds,
+                       'join_conds' => $joinConds
+               ];
+       }
+
+       public function usesTimestamps() {
+               return true;
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       public function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $d = $this->getLanguage()->userTimeAndDate( $result->value, $this->getUser() );
+               $title = Title::makeTitle( $result->namespace, $result->title );
+               $linkRenderer = $this->getLinkRenderer();
+               $link = $linkRenderer->makeKnownLink(
+                       $title,
+                       new HtmlArmor( MediaWikiServices::getInstance()->getContentLanguage()->
+                               convert( htmlspecialchars( $title->getPrefixedText() ) ) )
+               );
+
+               return $this->getLanguage()->specialList( $link, htmlspecialchars( $d ) );
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialAncientpages.php b/includes/specials/SpecialAncientpages.php
deleted file mode 100644 (file)
index a32393e..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-<?php
-/**
- * Implements Special:Ancientpages
- *
- * 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 SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * Implements Special:Ancientpages
- *
- * @ingroup SpecialPage
- */
-class AncientPagesPage extends QueryPage {
-
-       function __construct( $name = 'Ancientpages' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               $tables = [ 'page', 'revision' ];
-               $conds = [
-                       'page_namespace' =>
-                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces(),
-                       'page_is_redirect' => 0
-               ];
-               $joinConds = [
-                       'revision' => [
-                               'JOIN', [
-                                       'page_latest = rev_id'
-                               ]
-                       ],
-               ];
-
-               // Allow extensions to modify the query
-               Hooks::run( 'AncientPagesQuery', [ &$tables, &$conds, &$joinConds ] );
-
-               return [
-                       'tables' => $tables,
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'rev_timestamp'
-                       ],
-                       'conds' => $conds,
-                       'join_conds' => $joinConds
-               ];
-       }
-
-       public function usesTimestamps() {
-               return true;
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       public function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $d = $this->getLanguage()->userTimeAndDate( $result->value, $this->getUser() );
-               $title = Title::makeTitle( $result->namespace, $result->title );
-               $linkRenderer = $this->getLinkRenderer();
-               $link = $linkRenderer->makeKnownLink(
-                       $title,
-                       new HtmlArmor( MediaWikiServices::getInstance()->getContentLanguage()->
-                               convert( htmlspecialchars( $title->getPrefixedText() ) ) )
-               );
-
-               return $this->getLanguage()->specialList( $link, htmlspecialchars( $d ) );
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
index b3d2358..6385359 100644 (file)
@@ -82,8 +82,9 @@ class SpecialBlockList extends SpecialPage {
                        'Options' => [
                                'type' => 'multiselect',
                                'options-messages' => [
-                                       'blocklist-userblocks' => 'userblocks',
                                        'blocklist-tempblocks' => 'tempblocks',
+                                       'blocklist-indefblocks' => 'indefblocks',
+                                       'blocklist-userblocks' => 'userblocks',
                                        'blocklist-addressblocks' => 'addressblocks',
                                        'blocklist-rangeblocks' => 'rangeblocks',
                                ],
@@ -136,6 +137,7 @@ class SpecialBlockList extends SpecialPage {
         */
        protected function getBlockListPager() {
                $conds = [];
+               $db = $this->getDB();
                # Is the user allowed to see hidden blocks?
                if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
                        $conds['ipb_deleted'] = 0;
@@ -153,7 +155,7 @@ class SpecialBlockList extends SpecialPage {
                                case DatabaseBlock::TYPE_IP:
                                case DatabaseBlock::TYPE_RANGE:
                                        list( $start, $end ) = IP::parseRange( $target );
-                                       $conds[] = wfGetDB( DB_REPLICA )->makeList(
+                                       $conds[] = $db->makeList(
                                                [
                                                        'ipb_address' => $target,
                                                        DatabaseBlock::getRangeCond( $start, $end )
@@ -174,9 +176,6 @@ class SpecialBlockList extends SpecialPage {
                if ( in_array( 'userblocks', $this->options ) ) {
                        $conds['ipb_user'] = 0;
                }
-               if ( in_array( 'tempblocks', $this->options ) ) {
-                       $conds['ipb_expiry'] = 'infinity';
-               }
                if ( in_array( 'addressblocks', $this->options ) ) {
                        $conds[] = "ipb_user != 0 OR ipb_range_end > ipb_range_start";
                }
@@ -184,10 +183,21 @@ class SpecialBlockList extends SpecialPage {
                        $conds[] = "ipb_range_end = ipb_range_start";
                }
 
+               $hideTemp = in_array( 'tempblocks', $this->options );
+               $hideIndef = in_array( 'indefblocks', $this->options );
+               if ( $hideTemp && $hideIndef ) {
+                       // If both types are hidden, ensure query doesn't produce any results
+                       $conds[] = '1=0';
+               } elseif ( $hideTemp ) {
+                       $conds['ipb_expiry'] = $db->getInfinity();
+               } elseif ( $hideIndef ) {
+                       $conds[] = "ipb_expiry != " . $db->addQuotes( $db->getInfinity() );
+               }
+
                if ( $this->blockType === 'sitewide' ) {
-                       $conds[] = 'ipb_sitewide = 1';
+                       $conds['ipb_sitewide'] = 1;
                } elseif ( $this->blockType === 'partial' ) {
-                       $conds[] = 'ipb_sitewide = 0';
+                       $conds['ipb_sitewide'] = 0;
                }
 
                return new BlockListPager( $this, $conds );
@@ -243,4 +253,13 @@ class SpecialBlockList extends SpecialPage {
        protected function getGroupName() {
                return 'users';
        }
+
+       /**
+        * Return a IDatabase object for reading
+        *
+        * @return IDatabase
+        */
+       protected function getDB() {
+               return wfGetDB( DB_REPLICA );
+       }
 }
index 17f89f9..9431cef 100644 (file)
@@ -30,7 +30,7 @@ use Wikimedia\Rdbms\IDatabase;
  *
  * @ingroup SpecialPage
  */
-class BrokenRedirectsPage extends QueryPage {
+class SpecialBrokenRedirects extends QueryPage {
        function __construct( $name = 'BrokenRedirects' ) {
                parent::__construct( $name );
        }
diff --git a/includes/specials/SpecialConfirmEmail.php b/includes/specials/SpecialConfirmEmail.php
new file mode 100644 (file)
index 0000000..f86a133
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+/**
+ * Implements Special:Confirmemail
+ *
+ * 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 SpecialPage
+ */
+
+/**
+ * Special page allows users to request email confirmation message, and handles
+ * processing of the confirmation code when the link in the email is followed
+ *
+ * @ingroup SpecialPage
+ * @author Brion Vibber
+ * @author Rob Church <robchur@gmail.com>
+ */
+class SpecialConfirmEmail extends UnlistedSpecialPage {
+       public function __construct() {
+               parent::__construct( 'Confirmemail', 'editmyprivateinfo' );
+       }
+
+       public function doesWrites() {
+               return true;
+       }
+
+       /**
+        * Main execution point
+        *
+        * @param null|string $code Confirmation code passed to the page
+        * @throws PermissionsError
+        * @throws ReadOnlyError
+        * @throws UserNotLoggedIn
+        */
+       function execute( $code ) {
+               // Ignore things like master queries/connections on GET requests.
+               // It's very convenient to just allow formless link usage.
+               $trxProfiler = Profiler::instance()->getTransactionProfiler();
+
+               $this->setHeaders();
+               $this->checkReadOnly();
+               $this->checkPermissions();
+
+               // This could also let someone check the current email address, so
+               // require both permissions.
+               if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) {
+                       throw new PermissionsError( 'viewmyprivateinfo' );
+               }
+
+               if ( $code === null || $code === '' ) {
+                       $this->requireLogin( 'confirmemail_needlogin' );
+                       if ( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) {
+                               $this->showRequestForm();
+                       } else {
+                               $this->getOutput()->addWikiMsg( 'confirmemail_noemail' );
+                       }
+               } else {
+                       $old = $trxProfiler->setSilenced( true );
+                       $this->attemptConfirm( $code );
+                       $trxProfiler->setSilenced( $old );
+               }
+       }
+
+       /**
+        * Show a nice form for the user to request a confirmation mail
+        */
+       function showRequestForm() {
+               $user = $this->getUser();
+               $out = $this->getOutput();
+
+               if ( !$user->isEmailConfirmed() ) {
+                       $descriptor = [];
+                       if ( $user->isEmailConfirmationPending() ) {
+                               $descriptor += [
+                                       'pending' => [
+                                               'type' => 'info',
+                                               'raw' => true,
+                                               'default' => "<div class=\"error mw-confirmemail-pending\">\n" .
+                                                       $this->msg( 'confirmemail_pending' )->escaped() .
+                                                       "\n</div>",
+                                       ],
+                               ];
+                       }
+
+                       $out->addWikiMsg( 'confirmemail_text' );
+                       $form = HTMLForm::factory( 'ooui', $descriptor, $this->getContext() );
+                       $form
+                               ->setMethod( 'post' )
+                               ->setAction( $this->getPageTitle()->getLocalURL() )
+                               ->setSubmitTextMsg( 'confirmemail_send' )
+                               ->setSubmitCallback( [ $this, 'submitSend' ] );
+
+                       $retval = $form->show();
+
+                       if ( $retval === true ) {
+                               // should never happen, but if so, don't let the user without any message
+                               $out->addWikiMsg( 'confirmemail_sent' );
+                       } elseif ( $retval instanceof Status && $retval->isGood() ) {
+                               $out->addWikiTextAsInterface( $retval->getValue() );
+                       }
+               } else {
+                       // date and time are separate parameters to facilitate localisation.
+                       // $time is kept for backward compat reasons.
+                       // 'emailauthenticated' is also used in SpecialPreferences.php
+                       $lang = $this->getLanguage();
+                       $emailAuthenticated = $user->getEmailAuthenticationTimestamp();
+                       $time = $lang->userTimeAndDate( $emailAuthenticated, $user );
+                       $d = $lang->userDate( $emailAuthenticated, $user );
+                       $t = $lang->userTime( $emailAuthenticated, $user );
+                       $out->addWikiMsg( 'emailauthenticated', $time, $d, $t );
+               }
+       }
+
+       /**
+        * Callback for HTMLForm send confirmation mail.
+        *
+        * @return Status Status object with the result
+        */
+       public function submitSend() {
+               $status = $this->getUser()->sendConfirmationMail();
+               if ( $status->isGood() ) {
+                       return Status::newGood( $this->msg( 'confirmemail_sent' )->text() );
+               } else {
+                       return Status::newFatal( new RawMessage(
+                               $status->getWikiText( 'confirmemail_sendfailed' )
+                       ) );
+               }
+       }
+
+       /**
+        * Attempt to confirm the user's email address and show success or failure
+        * as needed; if successful, take the user to log in
+        *
+        * @param string $code Confirmation code
+        */
+       private function attemptConfirm( $code ) {
+               $user = User::newFromConfirmationCode( $code, User::READ_EXCLUSIVE );
+               if ( !is_object( $user ) ) {
+                       $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
+
+                       return;
+               }
+
+               // rate limit email confirmations
+               if ( $user->pingLimiter( 'confirmemail' ) ) {
+                       $this->getOutput()->addWikiMsg( 'actionthrottledtext' );
+
+                       return;
+               }
+
+               $user->confirmEmail();
+               $user->saveSettings();
+               $message = $this->getUser()->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
+               $this->getOutput()->addWikiMsg( $message );
+
+               if ( !$this->getUser()->isLoggedIn() ) {
+                       $title = SpecialPage::getTitleFor( 'Userlogin' );
+                       $this->getOutput()->returnToMain( true, $title );
+               }
+       }
+}
diff --git a/includes/specials/SpecialConfirmemail.php b/includes/specials/SpecialConfirmemail.php
deleted file mode 100644 (file)
index 7f32719..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-/**
- * Implements Special:Confirmemail
- *
- * 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 SpecialPage
- */
-
-/**
- * Special page allows users to request email confirmation message, and handles
- * processing of the confirmation code when the link in the email is followed
- *
- * @ingroup SpecialPage
- * @author Brion Vibber
- * @author Rob Church <robchur@gmail.com>
- */
-class EmailConfirmation extends UnlistedSpecialPage {
-       public function __construct() {
-               parent::__construct( 'Confirmemail', 'editmyprivateinfo' );
-       }
-
-       public function doesWrites() {
-               return true;
-       }
-
-       /**
-        * Main execution point
-        *
-        * @param null|string $code Confirmation code passed to the page
-        * @throws PermissionsError
-        * @throws ReadOnlyError
-        * @throws UserNotLoggedIn
-        */
-       function execute( $code ) {
-               // Ignore things like master queries/connections on GET requests.
-               // It's very convenient to just allow formless link usage.
-               $trxProfiler = Profiler::instance()->getTransactionProfiler();
-
-               $this->setHeaders();
-               $this->checkReadOnly();
-               $this->checkPermissions();
-
-               // This could also let someone check the current email address, so
-               // require both permissions.
-               if ( !$this->getUser()->isAllowed( 'viewmyprivateinfo' ) ) {
-                       throw new PermissionsError( 'viewmyprivateinfo' );
-               }
-
-               if ( $code === null || $code === '' ) {
-                       $this->requireLogin( 'confirmemail_needlogin' );
-                       if ( Sanitizer::validateEmail( $this->getUser()->getEmail() ) ) {
-                               $this->showRequestForm();
-                       } else {
-                               $this->getOutput()->addWikiMsg( 'confirmemail_noemail' );
-                       }
-               } else {
-                       $old = $trxProfiler->setSilenced( true );
-                       $this->attemptConfirm( $code );
-                       $trxProfiler->setSilenced( $old );
-               }
-       }
-
-       /**
-        * Show a nice form for the user to request a confirmation mail
-        */
-       function showRequestForm() {
-               $user = $this->getUser();
-               $out = $this->getOutput();
-
-               if ( !$user->isEmailConfirmed() ) {
-                       $descriptor = [];
-                       if ( $user->isEmailConfirmationPending() ) {
-                               $descriptor += [
-                                       'pending' => [
-                                               'type' => 'info',
-                                               'raw' => true,
-                                               'default' => "<div class=\"error mw-confirmemail-pending\">\n" .
-                                                       $this->msg( 'confirmemail_pending' )->escaped() .
-                                                       "\n</div>",
-                                       ],
-                               ];
-                       }
-
-                       $out->addWikiMsg( 'confirmemail_text' );
-                       $form = HTMLForm::factory( 'ooui', $descriptor, $this->getContext() );
-                       $form
-                               ->setMethod( 'post' )
-                               ->setAction( $this->getPageTitle()->getLocalURL() )
-                               ->setSubmitTextMsg( 'confirmemail_send' )
-                               ->setSubmitCallback( [ $this, 'submitSend' ] );
-
-                       $retval = $form->show();
-
-                       if ( $retval === true ) {
-                               // should never happen, but if so, don't let the user without any message
-                               $out->addWikiMsg( 'confirmemail_sent' );
-                       } elseif ( $retval instanceof Status && $retval->isGood() ) {
-                               $out->addWikiTextAsInterface( $retval->getValue() );
-                       }
-               } else {
-                       // date and time are separate parameters to facilitate localisation.
-                       // $time is kept for backward compat reasons.
-                       // 'emailauthenticated' is also used in SpecialPreferences.php
-                       $lang = $this->getLanguage();
-                       $emailAuthenticated = $user->getEmailAuthenticationTimestamp();
-                       $time = $lang->userTimeAndDate( $emailAuthenticated, $user );
-                       $d = $lang->userDate( $emailAuthenticated, $user );
-                       $t = $lang->userTime( $emailAuthenticated, $user );
-                       $out->addWikiMsg( 'emailauthenticated', $time, $d, $t );
-               }
-       }
-
-       /**
-        * Callback for HTMLForm send confirmation mail.
-        *
-        * @return Status Status object with the result
-        */
-       public function submitSend() {
-               $status = $this->getUser()->sendConfirmationMail();
-               if ( $status->isGood() ) {
-                       return Status::newGood( $this->msg( 'confirmemail_sent' )->text() );
-               } else {
-                       return Status::newFatal( new RawMessage(
-                               $status->getWikiText( 'confirmemail_sendfailed' )
-                       ) );
-               }
-       }
-
-       /**
-        * Attempt to confirm the user's email address and show success or failure
-        * as needed; if successful, take the user to log in
-        *
-        * @param string $code Confirmation code
-        */
-       private function attemptConfirm( $code ) {
-               $user = User::newFromConfirmationCode( $code, User::READ_EXCLUSIVE );
-               if ( !is_object( $user ) ) {
-                       $this->getOutput()->addWikiMsg( 'confirmemail_invalid' );
-
-                       return;
-               }
-
-               // rate limit email confirmations
-               if ( $user->pingLimiter( 'confirmemail' ) ) {
-                       $this->getOutput()->addWikiMsg( 'actionthrottledtext' );
-
-                       return;
-               }
-
-               $user->confirmEmail();
-               $user->saveSettings();
-               $message = $this->getUser()->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
-               $this->getOutput()->addWikiMsg( $message );
-
-               if ( !$this->getUser()->isLoggedIn() ) {
-                       $title = SpecialPage::getTitleFor( 'Userlogin' );
-                       $this->getOutput()->returnToMain( true, $title );
-               }
-       }
-}
diff --git a/includes/specials/SpecialDeadendPages.php b/includes/specials/SpecialDeadendPages.php
new file mode 100644 (file)
index 0000000..9159442
--- /dev/null
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Implements Special:Deadenpages
+ *
+ * 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 SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * A special page that list pages that contain no link to other pages
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialDeadendPages extends PageQueryPage {
+
+       function __construct( $name = 'Deadendpages' ) {
+               parent::__construct( $name );
+       }
+
+       function getPageHeader() {
+               return $this->msg( 'deadendpagestext' )->parseAsBlock();
+       }
+
+       /**
+        * LEFT JOIN is expensive
+        *
+        * @return bool
+        */
+       function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       /**
+        * @return bool
+        */
+       function sortDescending() {
+               return false;
+       }
+
+       function getQueryInfo() {
+               return [
+                       'tables' => [ 'page', 'pagelinks' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title'
+                       ],
+                       'conds' => [
+                               'pl_from IS NULL',
+                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getContentNamespaces(),
+                               'page_is_redirect' => 0
+                       ],
+                       'join_conds' => [
+                               'pagelinks' => [
+                                       'LEFT JOIN',
+                                       [ 'page_id=pl_from' ]
+                               ]
+                       ]
+               ];
+       }
+
+       function getOrderFields() {
+               // For some crazy reason ordering by a constant
+               // causes a filesort
+               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getContentNamespaces() ) > 1
+               ) {
+                       return [ 'page_namespace', 'page_title' ];
+               } else {
+                       return [ 'page_title' ];
+               }
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialDeadendpages.php b/includes/specials/SpecialDeadendpages.php
deleted file mode 100644 (file)
index 2a967c5..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-<?php
-/**
- * Implements Special:Deadenpages
- *
- * 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 SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * A special page that list pages that contain no link to other pages
- *
- * @ingroup SpecialPage
- */
-class DeadendPagesPage extends PageQueryPage {
-
-       function __construct( $name = 'Deadendpages' ) {
-               parent::__construct( $name );
-       }
-
-       function getPageHeader() {
-               return $this->msg( 'deadendpagestext' )->parseAsBlock();
-       }
-
-       /**
-        * LEFT JOIN is expensive
-        *
-        * @return bool
-        */
-       function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       /**
-        * @return bool
-        */
-       function sortDescending() {
-               return false;
-       }
-
-       function getQueryInfo() {
-               return [
-                       'tables' => [ 'page', 'pagelinks' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title'
-                       ],
-                       'conds' => [
-                               'pl_from IS NULL',
-                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
-                                       getContentNamespaces(),
-                               'page_is_redirect' => 0
-                       ],
-                       'join_conds' => [
-                               'pagelinks' => [
-                                       'LEFT JOIN',
-                                       [ 'page_id=pl_from' ]
-                               ]
-                       ]
-               ];
-       }
-
-       function getOrderFields() {
-               // For some crazy reason ordering by a constant
-               // causes a filesort
-               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
-                       getContentNamespaces() ) > 1
-               ) {
-                       return [ 'page_namespace', 'page_title' ];
-               } else {
-                       return [ 'page_title' ];
-               }
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
index e9bf6a2..b2cd8c0 100644 (file)
@@ -28,7 +28,7 @@ use MediaWiki\MediaWikiServices;
  * Implements Special:DeletedContributions to display archived revisions
  * @ingroup SpecialPage
  */
-class DeletedContributionsPage extends SpecialPage {
+class SpecialDeletedContributions extends SpecialPage {
        /** @var FormOptions */
        protected $mOpts;
 
index fcf1bb2..cccca50 100644 (file)
@@ -30,7 +30,7 @@ use Wikimedia\Rdbms\IDatabase;
  *
  * @ingroup SpecialPage
  */
-class DoubleRedirectsPage extends QueryPage {
+class SpecialDoubleRedirects extends QueryPage {
        function __construct( $name = 'DoubleRedirects' ) {
                parent::__construct( $name );
        }
index c54abad..7b9ee1a 100644 (file)
@@ -27,7 +27,7 @@
  *
  * @ingroup SpecialPage
  */
-class EmailInvalidation extends UnlistedSpecialPage {
+class SpecialEmailInvalidate extends UnlistedSpecialPage {
        public function __construct() {
                parent::__construct( 'Invalidateemail', 'editmyprivateinfo' );
        }
diff --git a/includes/specials/SpecialFewestRevisions.php b/includes/specials/SpecialFewestRevisions.php
new file mode 100644 (file)
index 0000000..204d73a
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Implements Special:Fewestrevisions
+ *
+ * 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 SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Special page for listing the articles with the fewest revisions.
+ *
+ * @ingroup SpecialPage
+ * @author Martin Drashkov
+ */
+class SpecialFewestRevisions extends QueryPage {
+       function __construct( $name = 'Fewestrevisions' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'revision', 'page' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'COUNT(*)',
+                       ],
+                       'conds' => [
+                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getContentNamespaces(),
+                               'page_id = rev_page',
+                               'page_is_redirect = 0',
+                       ],
+                       'options' => [
+                               'GROUP BY' => [ 'page_namespace', 'page_title' ]
+                       ]
+               ];
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Database row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $nt = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$nt ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title
+                               )
+                       );
+               }
+               $linkRenderer = $this->getLinkRenderer();
+               $text = MediaWikiServices::getInstance()->getContentLanguage()->
+                       convert( htmlspecialchars( $nt->getPrefixedText() ) );
+               $plink = $linkRenderer->makeLink( $nt, new HtmlArmor( $text ) );
+
+               $nl = $this->msg( 'nrevisions' )->numParams( $result->value )->text();
+               $redirect = isset( $result->redirect ) && $result->redirect ?
+                       ' - ' . $this->msg( 'isredirect' )->escaped() : '';
+               $nlink = $linkRenderer->makeKnownLink(
+                       $nt,
+                       $nl,
+                       [],
+                       [ 'action' => 'history' ]
+               ) . $redirect;
+
+               return $this->getLanguage()->specialList( $plink, $nlink );
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialFewestrevisions.php b/includes/specials/SpecialFewestrevisions.php
deleted file mode 100644 (file)
index cf9da49..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-<?php
-/**
- * Implements Special:Fewestrevisions
- *
- * 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 SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * Special page for listing the articles with the fewest revisions.
- *
- * @ingroup SpecialPage
- * @author Martin Drashkov
- */
-class FewestrevisionsPage extends QueryPage {
-       function __construct( $name = 'Fewestrevisions' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'revision', 'page' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'COUNT(*)',
-                       ],
-                       'conds' => [
-                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
-                                       getContentNamespaces(),
-                               'page_id = rev_page',
-                               'page_is_redirect = 0',
-                       ],
-                       'options' => [
-                               'GROUP BY' => [ 'page_namespace', 'page_title' ]
-                       ]
-               ];
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Database row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $nt = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$nt ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title
-                               )
-                       );
-               }
-               $linkRenderer = $this->getLinkRenderer();
-               $text = MediaWikiServices::getInstance()->getContentLanguage()->
-                       convert( htmlspecialchars( $nt->getPrefixedText() ) );
-               $plink = $linkRenderer->makeLink( $nt, new HtmlArmor( $text ) );
-
-               $nl = $this->msg( 'nrevisions' )->numParams( $result->value )->text();
-               $redirect = isset( $result->redirect ) && $result->redirect ?
-                       ' - ' . $this->msg( 'isredirect' )->escaped() : '';
-               $nlink = $linkRenderer->makeKnownLink(
-                       $nt,
-                       $nl,
-                       [],
-                       [ 'action' => 'history' ]
-               ) . $redirect;
-
-               return $this->getLanguage()->specialList( $plink, $nlink );
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
index 5d8a415..f047e1f 100644 (file)
@@ -31,7 +31,7 @@ use MediaWiki\MediaWikiServices;
  *
  * @ingroup SpecialPage
  */
-class FileDuplicateSearchPage extends QueryPage {
+class SpecialFileDuplicateSearch extends QueryPage {
        protected $hash = '', $filename = '';
 
        /**
index d08fe5c..60aedda 100644 (file)
@@ -29,9 +29,15 @@ use Wikimedia\Rdbms\IDatabase;
  * Special:LinkSearch to search the external-links table.
  * @ingroup SpecialPage
  */
-class LinkSearchPage extends QueryPage {
+class SpecialLinkSearch extends QueryPage {
        /** @var array|bool */
        private $mungedQuery = false;
+       /** @var string|null */
+       private $mQuery;
+       /** @var int|null */
+       private $mNs;
+       /** @var string|null */
+       private $mProt;
 
        function setParams( $params ) {
                $this->mQuery = $params['query'];
index c7430cc..d93c570 100644 (file)
@@ -32,7 +32,7 @@ use Wikimedia\Rdbms\IDatabase;
  *   a duplicate of the current version of some other file.
  * @ingroup SpecialPage
  */
-class ListDuplicatedFilesPage extends QueryPage {
+class SpecialListDuplicatedFiles extends QueryPage {
        function __construct( $name = 'ListDuplicatedFiles' ) {
                parent::__construct( $name );
        }
diff --git a/includes/specials/SpecialListRedirects.php b/includes/specials/SpecialListRedirects.php
new file mode 100644 (file)
index 0000000..e686273
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+/**
+ * Implements Special:Listredirects
+ *
+ * Copyright © 2006 Rob Church
+ *
+ * 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 SpecialPage
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * Special:Listredirects - Lists all the redirects on the wiki.
+ * @ingroup SpecialPage
+ */
+class SpecialListRedirects extends QueryPage {
+       function __construct( $name = 'Listredirects' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'p1' => 'page', 'redirect', 'p2' => 'page' ],
+                       'fields' => [ 'namespace' => 'p1.page_namespace',
+                               'title' => 'p1.page_title',
+                               'value' => 'p1.page_title',
+                               'rd_namespace',
+                               'rd_title',
+                               'rd_fragment',
+                               'rd_interwiki',
+                               'redirid' => 'p2.page_id' ],
+                       'conds' => [ 'p1.page_is_redirect' => 1 ],
+                       'join_conds' => [ 'redirect' => [
+                               'LEFT JOIN', 'rd_from=p1.page_id' ],
+                               'p2' => [ 'LEFT JOIN', [
+                                       'p2.page_namespace=rd_namespace',
+                                       'p2.page_title=rd_title' ] ] ]
+               ];
+       }
+
+       function getOrderFields() {
+               return [ 'p1.page_namespace', 'p1.page_title' ];
+       }
+
+       /**
+        * Cache page existence for performance
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               if ( !$res->numRows() ) {
+                       return;
+               }
+
+               $batch = new LinkBatch;
+               foreach ( $res as $row ) {
+                       $batch->add( $row->namespace, $row->title );
+                       $redirTarget = $this->getRedirectTarget( $row );
+                       if ( $redirTarget ) {
+                               $batch->addObj( $redirTarget );
+                       }
+               }
+               $batch->execute();
+
+               // Back to start for display
+               $res->seek( 0 );
+       }
+
+       /**
+        * @param stdClass $row
+        * @return Title|null
+        */
+       protected function getRedirectTarget( $row ) {
+               if ( isset( $row->rd_title ) ) {
+                       return Title::makeTitle( $row->rd_namespace,
+                               $row->rd_title, $row->rd_fragment,
+                               $row->rd_interwiki
+                       );
+               } else {
+                       $title = Title::makeTitle( $row->namespace, $row->title );
+                       $article = WikiPage::factory( $title );
+
+                       return $article->getRedirectTarget();
+               }
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $linkRenderer = $this->getLinkRenderer();
+               # Make a link to the redirect itself
+               $rd_title = Title::makeTitle( $result->namespace, $result->title );
+               $rd_link = $linkRenderer->makeLink(
+                       $rd_title,
+                       null,
+                       [],
+                       [ 'redirect' => 'no' ]
+               );
+
+               # Find out where the redirect leads
+               $target = $this->getRedirectTarget( $result );
+               if ( $target ) {
+                       # Make a link to the destination page
+                       $lang = $this->getLanguage();
+                       $arr = $lang->getArrow() . $lang->getDirMark();
+                       $targetLink = $linkRenderer->makeLink( $target, $target->getFullText() );
+
+                       return "$rd_link $arr $targetLink";
+               } else {
+                       return "<del>$rd_link</del>";
+               }
+       }
+
+       public function execute( $par ) {
+               $this->addHelpLink( 'Help:Redirects' );
+               parent::execute( $par );
+       }
+
+       protected function getGroupName() {
+               return 'pages';
+       }
+}
diff --git a/includes/specials/SpecialListredirects.php b/includes/specials/SpecialListredirects.php
deleted file mode 100644 (file)
index 3284c57..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-<?php
-/**
- * Implements Special:Listredirects
- *
- * Copyright © 2006 Rob Church
- *
- * 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 SpecialPage
- * @author Rob Church <robchur@gmail.com>
- */
-
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * Special:Listredirects - Lists all the redirects on the wiki.
- * @ingroup SpecialPage
- */
-class ListredirectsPage extends QueryPage {
-       function __construct( $name = 'Listredirects' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'p1' => 'page', 'redirect', 'p2' => 'page' ],
-                       'fields' => [ 'namespace' => 'p1.page_namespace',
-                               'title' => 'p1.page_title',
-                               'value' => 'p1.page_title',
-                               'rd_namespace',
-                               'rd_title',
-                               'rd_fragment',
-                               'rd_interwiki',
-                               'redirid' => 'p2.page_id' ],
-                       'conds' => [ 'p1.page_is_redirect' => 1 ],
-                       'join_conds' => [ 'redirect' => [
-                               'LEFT JOIN', 'rd_from=p1.page_id' ],
-                               'p2' => [ 'LEFT JOIN', [
-                                       'p2.page_namespace=rd_namespace',
-                                       'p2.page_title=rd_title' ] ] ]
-               ];
-       }
-
-       function getOrderFields() {
-               return [ 'p1.page_namespace', 'p1.page_title' ];
-       }
-
-       /**
-        * Cache page existence for performance
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               if ( !$res->numRows() ) {
-                       return;
-               }
-
-               $batch = new LinkBatch;
-               foreach ( $res as $row ) {
-                       $batch->add( $row->namespace, $row->title );
-                       $redirTarget = $this->getRedirectTarget( $row );
-                       if ( $redirTarget ) {
-                               $batch->addObj( $redirTarget );
-                       }
-               }
-               $batch->execute();
-
-               // Back to start for display
-               $res->seek( 0 );
-       }
-
-       /**
-        * @param stdClass $row
-        * @return Title|null
-        */
-       protected function getRedirectTarget( $row ) {
-               if ( isset( $row->rd_title ) ) {
-                       return Title::makeTitle( $row->rd_namespace,
-                               $row->rd_title, $row->rd_fragment,
-                               $row->rd_interwiki
-                       );
-               } else {
-                       $title = Title::makeTitle( $row->namespace, $row->title );
-                       $article = WikiPage::factory( $title );
-
-                       return $article->getRedirectTarget();
-               }
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $linkRenderer = $this->getLinkRenderer();
-               # Make a link to the redirect itself
-               $rd_title = Title::makeTitle( $result->namespace, $result->title );
-               $rd_link = $linkRenderer->makeLink(
-                       $rd_title,
-                       null,
-                       [],
-                       [ 'redirect' => 'no' ]
-               );
-
-               # Find out where the redirect leads
-               $target = $this->getRedirectTarget( $result );
-               if ( $target ) {
-                       # Make a link to the destination page
-                       $lang = $this->getLanguage();
-                       $arr = $lang->getArrow() . $lang->getDirMark();
-                       $targetLink = $linkRenderer->makeLink( $target, $target->getFullText() );
-
-                       return "$rd_link $arr $targetLink";
-               } else {
-                       return "<del>$rd_link</del>";
-               }
-       }
-
-       public function execute( $par ) {
-               $this->addHelpLink( 'Help:Redirects' );
-               parent::execute( $par );
-       }
-
-       protected function getGroupName() {
-               return 'pages';
-       }
-}
diff --git a/includes/specials/SpecialLonelyPages.php b/includes/specials/SpecialLonelyPages.php
new file mode 100644 (file)
index 0000000..14f9435
--- /dev/null
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Implements Special:Lonelypaages
+ *
+ * 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 SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * A special page looking for articles with no article linking to them,
+ * thus being lonely.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialLonelyPages extends PageQueryPage {
+       function __construct( $name = 'Lonelypages' ) {
+               parent::__construct( $name );
+       }
+
+       function getPageHeader() {
+               return $this->msg( 'lonelypagestext' )->parseAsBlock();
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function getQueryInfo() {
+               $tables = [ 'page', 'pagelinks', 'templatelinks' ];
+               $conds = [
+                       'pl_namespace IS NULL',
+                       'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getContentNamespaces(),
+                       'page_is_redirect' => 0,
+                       'tl_namespace IS NULL'
+               ];
+               $joinConds = [
+                       'pagelinks' => [
+                               'LEFT JOIN', [
+                                       'pl_namespace = page_namespace',
+                                       'pl_title = page_title'
+                               ]
+                       ],
+                       'templatelinks' => [
+                               'LEFT JOIN', [
+                                       'tl_namespace = page_namespace',
+                                       'tl_title = page_title'
+                               ]
+                       ]
+               ];
+
+               // Allow extensions to modify the query
+               Hooks::run( 'LonelyPagesQuery', [ &$tables, &$conds, &$joinConds ] );
+
+               return [
+                       'tables' => $tables,
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title'
+                       ],
+                       'conds' => $conds,
+                       'join_conds' => $joinConds
+               ];
+       }
+
+       function getOrderFields() {
+               // For some crazy reason ordering by a constant
+               // causes a filesort in MySQL 5
+               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                       getContentNamespaces() ) > 1
+               ) {
+                       return [ 'page_namespace', 'page_title' ];
+               } else {
+                       return [ 'page_title' ];
+               }
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialLonelypages.php b/includes/specials/SpecialLonelypages.php
deleted file mode 100644 (file)
index ca3f4da..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-/**
- * Implements Special:Lonelypaages
- *
- * 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 SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * A special page looking for articles with no article linking to them,
- * thus being lonely.
- *
- * @ingroup SpecialPage
- */
-class LonelyPagesPage extends PageQueryPage {
-       function __construct( $name = 'Lonelypages' ) {
-               parent::__construct( $name );
-       }
-
-       function getPageHeader() {
-               return $this->msg( 'lonelypagestext' )->parseAsBlock();
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function getQueryInfo() {
-               $tables = [ 'page', 'pagelinks', 'templatelinks' ];
-               $conds = [
-                       'pl_namespace IS NULL',
-                       'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
-                               getContentNamespaces(),
-                       'page_is_redirect' => 0,
-                       'tl_namespace IS NULL'
-               ];
-               $joinConds = [
-                       'pagelinks' => [
-                               'LEFT JOIN', [
-                                       'pl_namespace = page_namespace',
-                                       'pl_title = page_title'
-                               ]
-                       ],
-                       'templatelinks' => [
-                               'LEFT JOIN', [
-                                       'tl_namespace = page_namespace',
-                                       'tl_title = page_title'
-                               ]
-                       ]
-               ];
-
-               // Allow extensions to modify the query
-               Hooks::run( 'LonelyPagesQuery', [ &$tables, &$conds, &$joinConds ] );
-
-               return [
-                       'tables' => $tables,
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title'
-                       ],
-                       'conds' => $conds,
-                       'join_conds' => $joinConds
-               ];
-       }
-
-       function getOrderFields() {
-               // For some crazy reason ordering by a constant
-               // causes a filesort in MySQL 5
-               if ( count( MediaWikiServices::getInstance()->getNamespaceInfo()->
-                       getContentNamespaces() ) > 1
-               ) {
-                       return [ 'page_namespace', 'page_title' ];
-               } else {
-                       return [ 'page_title' ];
-               }
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialLongPages.php b/includes/specials/SpecialLongPages.php
new file mode 100644 (file)
index 0000000..5227d4e
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Implements Special:Longpages
+ *
+ * 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 SpecialPage
+ */
+
+/**
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialLongPages extends SpecialShortPages {
+       function __construct( $name = 'Longpages' ) {
+               parent::__construct( $name );
+       }
+
+       function sortDescending() {
+               return true;
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialLongpages.php b/includes/specials/SpecialLongpages.php
deleted file mode 100644 (file)
index d90d271..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/**
- * Implements Special:Longpages
- *
- * 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 SpecialPage
- */
-
-/**
- *
- * @ingroup SpecialPage
- */
-class LongPagesPage extends ShortPagesPage {
-       function __construct( $name = 'Longpages' ) {
-               parent::__construct( $name );
-       }
-
-       function sortDescending() {
-               return true;
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialMIMESearch.php b/includes/specials/SpecialMIMESearch.php
new file mode 100644 (file)
index 0000000..0784821
--- /dev/null
@@ -0,0 +1,244 @@
+<?php
+/**
+ * Implements Special:MIMESearch
+ *
+ * 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 SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Searches the database for files of the requested MIME type, comparing this with the
+ * 'img_major_mime' and 'img_minor_mime' fields in the image table.
+ * @ingroup SpecialPage
+ */
+class SpecialMIMESearch extends QueryPage {
+       protected $major, $minor, $mime;
+
+       function __construct( $name = 'MIMEsearch' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return false;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function isCacheable() {
+               return false;
+       }
+
+       function linkParameters() {
+               return [ 'mime' => "{$this->major}/{$this->minor}" ];
+       }
+
+       public function getQueryInfo() {
+               $minorType = [];
+               if ( $this->minor !== '*' ) {
+                       // Allow wildcard searching
+                       $minorType['img_minor_mime'] = $this->minor;
+               }
+               $imgQuery = LocalFile::getQueryInfo();
+               $qi = [
+                       'tables' => $imgQuery['tables'],
+                       'fields' => [
+                               'namespace' => NS_FILE,
+                               'title' => 'img_name',
+                               // Still have a value field just in case,
+                               // but it isn't actually used for sorting.
+                               'value' => 'img_name',
+                               'img_size',
+                               'img_width',
+                               'img_height',
+                               'img_user_text' => $imgQuery['fields']['img_user_text'],
+                               'img_timestamp'
+                       ],
+                       'conds' => [
+                               'img_major_mime' => $this->major,
+                               // This is in order to trigger using
+                               // the img_media_mime index in "range" mode.
+                               // @todo how is order defined? use MimeAnalyzer::getMediaTypes?
+                               'img_media_type' => [
+                                       MEDIATYPE_BITMAP,
+                                       MEDIATYPE_DRAWING,
+                                       MEDIATYPE_AUDIO,
+                                       MEDIATYPE_VIDEO,
+                                       MEDIATYPE_MULTIMEDIA,
+                                       MEDIATYPE_UNKNOWN,
+                                       MEDIATYPE_OFFICE,
+                                       MEDIATYPE_TEXT,
+                                       MEDIATYPE_EXECUTABLE,
+                                       MEDIATYPE_ARCHIVE,
+                                       MEDIATYPE_3D,
+                               ],
+                       ] + $minorType,
+                       'join_conds' => $imgQuery['joins'],
+               ];
+
+               return $qi;
+       }
+
+       /**
+        * The index is on (img_media_type, img_major_mime, img_minor_mime)
+        * which unfortunately doesn't have img_name at the end for sorting.
+        * So tell db to sort it however it wishes (Its not super important
+        * that this report gives results in a logical order). As an aditional
+        * note, mysql seems to by default order things by img_name ASC, which
+        * is what we ideally want, so everything works out fine anyhow.
+        * @return array
+        */
+       function getOrderFields() {
+               return [];
+       }
+
+       /**
+        * Generate and output the form
+        */
+       function getPageHeader() {
+               $formDescriptor = [
+                       'mime' => [
+                               'type' => 'combobox',
+                               'options' => $this->getSuggestionsForTypes(),
+                               'name' => 'mime',
+                               'label-message' => 'mimetype',
+                               'required' => true,
+                               'default' => $this->mime,
+                       ],
+               ];
+
+               HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
+                       ->setSubmitTextMsg( 'ilsubmit' )
+                       ->setAction( $this->getPageTitle()->getLocalURL() )
+                       ->setMethod( 'get' )
+                       ->prepareForm()
+                       ->displayForm( false );
+               return '';
+       }
+
+       protected function getSuggestionsForTypes() {
+               $dbr = wfGetDB( DB_REPLICA );
+               $lastMajor = null;
+               $suggestions = [];
+               $result = $dbr->select(
+                       [ 'image' ],
+                       // We ignore img_media_type, but using it in the query is needed for MySQL to choose a
+                       // sensible execution plan
+                       [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ],
+                       [],
+                       __METHOD__,
+                       [ 'GROUP BY' => [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ] ]
+               );
+               foreach ( $result as $row ) {
+                       $major = $row->img_major_mime;
+                       $minor = $row->img_minor_mime;
+                       $suggestions[ "$major/$minor" ] = "$major/$minor";
+                       if ( $lastMajor === $major ) {
+                               // If there are at least two with the same major mime type, also include the wildcard
+                               $suggestions[ "$major/*" ] = "$major/*";
+                       }
+                       $lastMajor = $major;
+               }
+               ksort( $suggestions );
+               return $suggestions;
+       }
+
+       public function execute( $par ) {
+               $this->addHelpLink( 'Help:Managing_files' );
+               $this->mime = $par ?: $this->getRequest()->getText( 'mime' );
+               $this->mime = trim( $this->mime );
+               list( $this->major, $this->minor ) = File::splitMime( $this->mime );
+
+               if ( $this->major == '' || $this->minor == '' || $this->minor == 'unknown' ||
+                       !self::isValidType( $this->major )
+               ) {
+                       $this->setHeaders();
+                       $this->outputHeader();
+                       $this->getPageHeader();
+                       return;
+               }
+
+               parent::execute( $par );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $linkRenderer = $this->getLinkRenderer();
+               $nt = Title::makeTitle( $result->namespace, $result->title );
+               $text = MediaWikiServices::getInstance()->getContentLanguage()
+                       ->convert( htmlspecialchars( $nt->getText() ) );
+               $plink = $linkRenderer->makeLink(
+                       Title::newFromText( $nt->getPrefixedText() ),
+                       new HtmlArmor( $text )
+               );
+
+               $download = Linker::makeMediaLinkObj( $nt, $this->msg( 'download' )->escaped() );
+               $download = $this->msg( 'parentheses' )->rawParams( $download )->escaped();
+               $lang = $this->getLanguage();
+               $bytes = htmlspecialchars( $lang->formatSize( $result->img_size ) );
+               $dimensions = $this->msg( 'widthheight' )->numParams( $result->img_width,
+                       $result->img_height )->escaped();
+               $user = $linkRenderer->makeLink(
+                       Title::makeTitle( NS_USER, $result->img_user_text ),
+                       $result->img_user_text
+               );
+
+               $time = $lang->userTimeAndDate( $result->img_timestamp, $this->getUser() );
+               $time = htmlspecialchars( $time );
+
+               return "$download $plink . . $dimensions . . $bytes . . $user . . $time";
+       }
+
+       /**
+        * @param string $type
+        * @return bool
+        */
+       protected static function isValidType( $type ) {
+               // From maintenance/tables.sql => img_major_mime
+               $types = [
+                       'unknown',
+                       'application',
+                       'audio',
+                       'image',
+                       'text',
+                       'video',
+                       'message',
+                       'model',
+                       'multipart',
+                       'chemical'
+               ];
+
+               return in_array( $type, $types );
+       }
+
+       public function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       protected function getGroupName() {
+               return 'media';
+       }
+}
diff --git a/includes/specials/SpecialMIMEsearch.php b/includes/specials/SpecialMIMEsearch.php
deleted file mode 100644 (file)
index d6ace1d..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-<?php
-/**
- * Implements Special:MIMESearch
- *
- * 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 SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * Searches the database for files of the requested MIME type, comparing this with the
- * 'img_major_mime' and 'img_minor_mime' fields in the image table.
- * @ingroup SpecialPage
- */
-class MIMEsearchPage extends QueryPage {
-       protected $major, $minor, $mime;
-
-       function __construct( $name = 'MIMEsearch' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return false;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function isCacheable() {
-               return false;
-       }
-
-       function linkParameters() {
-               return [ 'mime' => "{$this->major}/{$this->minor}" ];
-       }
-
-       public function getQueryInfo() {
-               $minorType = [];
-               if ( $this->minor !== '*' ) {
-                       // Allow wildcard searching
-                       $minorType['img_minor_mime'] = $this->minor;
-               }
-               $imgQuery = LocalFile::getQueryInfo();
-               $qi = [
-                       'tables' => $imgQuery['tables'],
-                       'fields' => [
-                               'namespace' => NS_FILE,
-                               'title' => 'img_name',
-                               // Still have a value field just in case,
-                               // but it isn't actually used for sorting.
-                               'value' => 'img_name',
-                               'img_size',
-                               'img_width',
-                               'img_height',
-                               'img_user_text' => $imgQuery['fields']['img_user_text'],
-                               'img_timestamp'
-                       ],
-                       'conds' => [
-                               'img_major_mime' => $this->major,
-                               // This is in order to trigger using
-                               // the img_media_mime index in "range" mode.
-                               // @todo how is order defined? use MimeAnalyzer::getMediaTypes?
-                               'img_media_type' => [
-                                       MEDIATYPE_BITMAP,
-                                       MEDIATYPE_DRAWING,
-                                       MEDIATYPE_AUDIO,
-                                       MEDIATYPE_VIDEO,
-                                       MEDIATYPE_MULTIMEDIA,
-                                       MEDIATYPE_UNKNOWN,
-                                       MEDIATYPE_OFFICE,
-                                       MEDIATYPE_TEXT,
-                                       MEDIATYPE_EXECUTABLE,
-                                       MEDIATYPE_ARCHIVE,
-                                       MEDIATYPE_3D,
-                               ],
-                       ] + $minorType,
-                       'join_conds' => $imgQuery['joins'],
-               ];
-
-               return $qi;
-       }
-
-       /**
-        * The index is on (img_media_type, img_major_mime, img_minor_mime)
-        * which unfortunately doesn't have img_name at the end for sorting.
-        * So tell db to sort it however it wishes (Its not super important
-        * that this report gives results in a logical order). As an aditional
-        * note, mysql seems to by default order things by img_name ASC, which
-        * is what we ideally want, so everything works out fine anyhow.
-        * @return array
-        */
-       function getOrderFields() {
-               return [];
-       }
-
-       /**
-        * Generate and output the form
-        */
-       function getPageHeader() {
-               $formDescriptor = [
-                       'mime' => [
-                               'type' => 'combobox',
-                               'options' => $this->getSuggestionsForTypes(),
-                               'name' => 'mime',
-                               'label-message' => 'mimetype',
-                               'required' => true,
-                               'default' => $this->mime,
-                       ],
-               ];
-
-               HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
-                       ->setSubmitTextMsg( 'ilsubmit' )
-                       ->setAction( $this->getPageTitle()->getLocalURL() )
-                       ->setMethod( 'get' )
-                       ->prepareForm()
-                       ->displayForm( false );
-               return '';
-       }
-
-       protected function getSuggestionsForTypes() {
-               $dbr = wfGetDB( DB_REPLICA );
-               $lastMajor = null;
-               $suggestions = [];
-               $result = $dbr->select(
-                       [ 'image' ],
-                       // We ignore img_media_type, but using it in the query is needed for MySQL to choose a
-                       // sensible execution plan
-                       [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ],
-                       [],
-                       __METHOD__,
-                       [ 'GROUP BY' => [ 'img_media_type', 'img_major_mime', 'img_minor_mime' ] ]
-               );
-               foreach ( $result as $row ) {
-                       $major = $row->img_major_mime;
-                       $minor = $row->img_minor_mime;
-                       $suggestions[ "$major/$minor" ] = "$major/$minor";
-                       if ( $lastMajor === $major ) {
-                               // If there are at least two with the same major mime type, also include the wildcard
-                               $suggestions[ "$major/*" ] = "$major/*";
-                       }
-                       $lastMajor = $major;
-               }
-               ksort( $suggestions );
-               return $suggestions;
-       }
-
-       public function execute( $par ) {
-               $this->addHelpLink( 'Help:Managing_files' );
-               $this->mime = $par ?: $this->getRequest()->getText( 'mime' );
-               $this->mime = trim( $this->mime );
-               list( $this->major, $this->minor ) = File::splitMime( $this->mime );
-
-               if ( $this->major == '' || $this->minor == '' || $this->minor == 'unknown' ||
-                       !self::isValidType( $this->major )
-               ) {
-                       $this->setHeaders();
-                       $this->outputHeader();
-                       $this->getPageHeader();
-                       return;
-               }
-
-               parent::execute( $par );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $linkRenderer = $this->getLinkRenderer();
-               $nt = Title::makeTitle( $result->namespace, $result->title );
-               $text = MediaWikiServices::getInstance()->getContentLanguage()
-                       ->convert( htmlspecialchars( $nt->getText() ) );
-               $plink = $linkRenderer->makeLink(
-                       Title::newFromText( $nt->getPrefixedText() ),
-                       new HtmlArmor( $text )
-               );
-
-               $download = Linker::makeMediaLinkObj( $nt, $this->msg( 'download' )->escaped() );
-               $download = $this->msg( 'parentheses' )->rawParams( $download )->escaped();
-               $lang = $this->getLanguage();
-               $bytes = htmlspecialchars( $lang->formatSize( $result->img_size ) );
-               $dimensions = $this->msg( 'widthheight' )->numParams( $result->img_width,
-                       $result->img_height )->escaped();
-               $user = $linkRenderer->makeLink(
-                       Title::makeTitle( NS_USER, $result->img_user_text ),
-                       $result->img_user_text
-               );
-
-               $time = $lang->userTimeAndDate( $result->img_timestamp, $this->getUser() );
-               $time = htmlspecialchars( $time );
-
-               return "$download $plink . . $dimensions . . $bytes . . $user . . $time";
-       }
-
-       /**
-        * @param string $type
-        * @return bool
-        */
-       protected static function isValidType( $type ) {
-               // From maintenance/tables.sql => img_major_mime
-               $types = [
-                       'unknown',
-                       'application',
-                       'audio',
-                       'image',
-                       'text',
-                       'video',
-                       'message',
-                       'model',
-                       'multipart',
-                       'chemical'
-               ];
-
-               return in_array( $type, $types );
-       }
-
-       public function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       protected function getGroupName() {
-               return 'media';
-       }
-}
index 45bd524..333d9b3 100644 (file)
@@ -28,7 +28,7 @@ use Wikimedia\Rdbms\IDatabase;
 /**
  * @ingroup SpecialPage
  */
-class MediaStatisticsPage extends QueryPage {
+class SpecialMediaStatistics extends QueryPage {
        protected $totalCount = 0, $totalBytes = 0;
 
        /**
diff --git a/includes/specials/SpecialMostCategories.php b/includes/specials/SpecialMostCategories.php
new file mode 100644 (file)
index 0000000..682a23a
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Implements Special:Mostcategories
+ *
+ * Copyright © 2005 Ævar Arnfjörð Bjarmason
+ *
+ * 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 SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A special page that list pages that have highest category count
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostCategories extends QueryPage {
+       function __construct( $name = 'Mostcategories' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'categorylinks', 'page' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'COUNT(*)'
+                       ],
+                       'conds' => [ 'page_namespace' =>
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces() ],
+                       'options' => [
+                               'HAVING' => 'COUNT(*) > 1',
+                               'GROUP BY' => [ 'page_namespace', 'page_title' ]
+                       ],
+                       'join_conds' => [
+                               'page' => [
+                                       'LEFT JOIN',
+                                       'page_id = cl_from'
+                               ]
+                       ]
+               ];
+       }
+
+       /**
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $title = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$title ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title
+                               )
+                       );
+               }
+
+               $linkRenderer = $this->getLinkRenderer();
+               if ( $this->isCached() ) {
+                       $link = $linkRenderer->makeLink( $title );
+               } else {
+                       $link = $linkRenderer->makeKnownLink( $title );
+               }
+
+               $count = $this->msg( 'ncategories' )->numParams( $result->value )->escaped();
+
+               return $this->getLanguage()->specialList( $link, $count );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostInterwikis.php b/includes/specials/SpecialMostInterwikis.php
new file mode 100644 (file)
index 0000000..52777b0
--- /dev/null
@@ -0,0 +1,117 @@
+<?php
+/**
+ * Implements Special:Mostinterwikis
+ *
+ * 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 SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A special page that listed pages that have highest interwiki count
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostInterwikis extends QueryPage {
+       function __construct( $name = 'Mostinterwikis' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [
+                               'langlinks',
+                               'page'
+                       ], 'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'COUNT(*)'
+                       ], 'conds' => [
+                               'page_namespace' =>
+                                       MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces()
+                       ], 'options' => [
+                               'HAVING' => 'COUNT(*) > 1',
+                               'GROUP BY' => [
+                                       'page_namespace',
+                                       'page_title'
+                               ]
+                       ], 'join_conds' => [
+                               'page' => [
+                                       'LEFT JOIN',
+                                       'page_id = ll_from'
+                               ]
+                       ]
+               ];
+       }
+
+       /**
+        * Pre-fill the link cache
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $title = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$title ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title
+                               )
+                       );
+               }
+
+               $linkRenderer = $this->getLinkRenderer();
+               if ( $this->isCached() ) {
+                       $link = $linkRenderer->makeLink( $title );
+               } else {
+                       $link = $linkRenderer->makeKnownLink( $title );
+               }
+
+               $count = $this->msg( 'ninterwikis' )->numParams( $result->value )->escaped();
+
+               return $this->getLanguage()->specialList( $link, $count );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostLinked.php b/includes/specials/SpecialMostLinked.php
new file mode 100644 (file)
index 0000000..c0f1a2a
--- /dev/null
@@ -0,0 +1,135 @@
+<?php
+/**
+ * Implements Special:Mostlinked
+ *
+ * Copyright © 2005 Ævar Arnfjörð Bjarmason, 2006 Rob Church
+ *
+ * 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 SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A special page to show pages ordered by the number of pages linking to them.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostLinked extends QueryPage {
+       function __construct( $name = 'Mostlinked' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'pagelinks', 'page' ],
+                       'fields' => [
+                               'namespace' => 'pl_namespace',
+                               'title' => 'pl_title',
+                               'value' => 'COUNT(*)',
+                               'page_namespace'
+                       ],
+                       'options' => [
+                               'HAVING' => 'COUNT(*) > 1',
+                               'GROUP BY' => [
+                                       'pl_namespace', 'pl_title',
+                                       'page_namespace'
+                               ]
+                       ],
+                       'join_conds' => [
+                               'page' => [
+                                       'LEFT JOIN',
+                                       [
+                                               'page_namespace = pl_namespace',
+                                               'page_title = pl_title'
+                                       ]
+                               ]
+                       ]
+               ];
+       }
+
+       /**
+        * Pre-fill the link cache
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * Make a link to "what links here" for the specified title
+        *
+        * @param Title $title Title being queried
+        * @param string $caption Text to display on the link
+        * @return string
+        */
+       function makeWlhLink( $title, $caption ) {
+               $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedDBkey() );
+
+               $linkRenderer = $this->getLinkRenderer();
+               return $linkRenderer->makeKnownLink( $wlh, $caption );
+       }
+
+       /**
+        * Make links to the page corresponding to the item,
+        * and the "what links here" page for it
+        *
+        * @param Skin $skin Skin to be used
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $title = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$title ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title )
+                       );
+               }
+
+               $linkRenderer = $this->getLinkRenderer();
+               $link = $linkRenderer->makeLink( $title );
+               $wlh = $this->makeWlhLink(
+                       $title,
+                       $this->msg( 'nlinks' )->numParams( $result->value )->text()
+               );
+
+               return $this->getLanguage()->specialList( $link, $wlh );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostLinkedCategories.php b/includes/specials/SpecialMostLinkedCategories.php
new file mode 100644 (file)
index 0000000..32157fa
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Implements Special:Mostlinkedcategories
+ *
+ * Copyright © 2005, Ævar Arnfjörð Bjarmason
+ *
+ * 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 SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A querypage to show categories ordered in descending order by the pages in them
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostLinkedCategories extends QueryPage {
+       function __construct( $name = 'Mostlinkedcategories' ) {
+               parent::__construct( $name );
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'category' ],
+                       'fields' => [ 'title' => 'cat_title',
+                               'namespace' => NS_CATEGORY,
+                               'value' => 'cat_pages' ],
+                       'conds' => [ 'cat_pages > 0' ],
+               ];
+       }
+
+       function sortDescending() {
+               return true;
+       }
+
+       /**
+        * Fetch user page links and cache their existence
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $nt = Title::makeTitleSafe( NS_CATEGORY, $result->title );
+               if ( !$nt ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       NS_CATEGORY,
+                                       $result->title )
+                       );
+               }
+
+               $text = MediaWikiServices::getInstance()->getContentLanguage()
+                       ->convert( htmlspecialchars( $nt->getText() ) );
+               $plink = $this->getLinkRenderer()->makeLink( $nt, new HtmlArmor( $text ) );
+               $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped();
+
+               return $this->getLanguage()->specialList( $plink, $nlinks );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostLinkedTemplates.php b/includes/specials/SpecialMostLinkedTemplates.php
new file mode 100644 (file)
index 0000000..f7122c2
--- /dev/null
@@ -0,0 +1,132 @@
+<?php
+/**
+ * Implements Special:Mostlinkedtemplates
+ *
+ * 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 SpecialPage
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * Special page lists templates with a large number of
+ * transclusion links, i.e. "most used" templates
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialMostLinkedTemplates extends QueryPage {
+       function __construct( $name = 'Mostlinkedtemplates' ) {
+               parent::__construct( $name );
+       }
+
+       /**
+        * Is this report expensive, i.e should it be cached?
+        *
+        * @return bool
+        */
+       public function isExpensive() {
+               return true;
+       }
+
+       /**
+        * Is there a feed available?
+        *
+        * @return bool
+        */
+       public function isSyndicated() {
+               return false;
+       }
+
+       /**
+        * Sort the results in descending order?
+        *
+        * @return bool
+        */
+       public function sortDescending() {
+               return true;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'templatelinks' ],
+                       'fields' => [
+                               'namespace' => 'tl_namespace',
+                               'title' => 'tl_title',
+                               'value' => 'COUNT(*)'
+                       ],
+                       'options' => [ 'GROUP BY' => [ 'tl_namespace', 'tl_title' ] ]
+               ];
+       }
+
+       /**
+        * Pre-cache page existence to speed up link generation
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       public function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       /**
+        * Format a result row
+        *
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       public function formatResult( $skin, $result ) {
+               $title = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$title ) {
+                       return Html::element(
+                               'span',
+                               [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription(
+                                       $this->getContext(),
+                                       $result->namespace,
+                                       $result->title
+                               )
+                       );
+               }
+
+               return $this->getLanguage()->specialList(
+                       $this->getLinkRenderer()->makeLink( $title ),
+                       $this->makeWlhLink( $title, $result )
+               );
+       }
+
+       /**
+        * Make a "what links here" link for a given title
+        *
+        * @param Title $title Title to make the link for
+        * @param object $result Result row
+        * @return string
+        */
+       private function makeWlhLink( $title, $result ) {
+               $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() );
+               $label = $this->msg( 'ntransclusions' )->numParams( $result->value )->text();
+
+               return $this->getLinkRenderer()->makeLink( $wlh, $label );
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostRevisions.php b/includes/specials/SpecialMostRevisions.php
new file mode 100644 (file)
index 0000000..60e0fe7
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Implements Special:Mostrevisions
+ *
+ * Copyright © 2005 Ævar Arnfjörð Bjarmason
+ *
+ * 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 SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ */
+
+class SpecialMostRevisions extends SpecialFewestRevisions {
+       function __construct( $name = 'Mostrevisions' ) {
+               parent::__construct( $name );
+       }
+
+       function sortDescending() {
+               return true;
+       }
+
+       protected function getGroupName() {
+               return 'highuse';
+       }
+}
diff --git a/includes/specials/SpecialMostcategories.php b/includes/specials/SpecialMostcategories.php
deleted file mode 100644 (file)
index 0dd9437..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-/**
- * Implements Special:Mostcategories
- *
- * Copyright © 2005 Ævar Arnfjörð Bjarmason
- *
- * 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 SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * A special page that list pages that have highest category count
- *
- * @ingroup SpecialPage
- */
-class MostcategoriesPage extends QueryPage {
-       function __construct( $name = 'Mostcategories' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'categorylinks', 'page' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'COUNT(*)'
-                       ],
-                       'conds' => [ 'page_namespace' =>
-                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces() ],
-                       'options' => [
-                               'HAVING' => 'COUNT(*) > 1',
-                               'GROUP BY' => [ 'page_namespace', 'page_title' ]
-                       ],
-                       'join_conds' => [
-                               'page' => [
-                                       'LEFT JOIN',
-                                       'page_id = cl_from'
-                               ]
-                       ]
-               ];
-       }
-
-       /**
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $title = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$title ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title
-                               )
-                       );
-               }
-
-               $linkRenderer = $this->getLinkRenderer();
-               if ( $this->isCached() ) {
-                       $link = $linkRenderer->makeLink( $title );
-               } else {
-                       $link = $linkRenderer->makeKnownLink( $title );
-               }
-
-               $count = $this->msg( 'ncategories' )->numParams( $result->value )->escaped();
-
-               return $this->getLanguage()->specialList( $link, $count );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostinterwikis.php b/includes/specials/SpecialMostinterwikis.php
deleted file mode 100644 (file)
index 0fcf842..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-<?php
-/**
- * Implements Special:Mostinterwikis
- *
- * 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 SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * A special page that listed pages that have highest interwiki count
- *
- * @ingroup SpecialPage
- */
-class MostinterwikisPage extends QueryPage {
-       function __construct( $name = 'Mostinterwikis' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [
-                               'langlinks',
-                               'page'
-                       ], 'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'COUNT(*)'
-                       ], 'conds' => [
-                               'page_namespace' =>
-                                       MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces()
-                       ], 'options' => [
-                               'HAVING' => 'COUNT(*) > 1',
-                               'GROUP BY' => [
-                                       'page_namespace',
-                                       'page_title'
-                               ]
-                       ], 'join_conds' => [
-                               'page' => [
-                                       'LEFT JOIN',
-                                       'page_id = ll_from'
-                               ]
-                       ]
-               ];
-       }
-
-       /**
-        * Pre-fill the link cache
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $title = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$title ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title
-                               )
-                       );
-               }
-
-               $linkRenderer = $this->getLinkRenderer();
-               if ( $this->isCached() ) {
-                       $link = $linkRenderer->makeLink( $title );
-               } else {
-                       $link = $linkRenderer->makeKnownLink( $title );
-               }
-
-               $count = $this->msg( 'ninterwikis' )->numParams( $result->value )->escaped();
-
-               return $this->getLanguage()->specialList( $link, $count );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostlinked.php b/includes/specials/SpecialMostlinked.php
deleted file mode 100644 (file)
index c4553a4..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-/**
- * Implements Special:Mostlinked
- *
- * Copyright © 2005 Ævar Arnfjörð Bjarmason, 2006 Rob Church
- *
- * 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 SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- * @author Rob Church <robchur@gmail.com>
- */
-
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * A special page to show pages ordered by the number of pages linking to them.
- *
- * @ingroup SpecialPage
- */
-class MostlinkedPage extends QueryPage {
-       function __construct( $name = 'Mostlinked' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'pagelinks', 'page' ],
-                       'fields' => [
-                               'namespace' => 'pl_namespace',
-                               'title' => 'pl_title',
-                               'value' => 'COUNT(*)',
-                               'page_namespace'
-                       ],
-                       'options' => [
-                               'HAVING' => 'COUNT(*) > 1',
-                               'GROUP BY' => [
-                                       'pl_namespace', 'pl_title',
-                                       'page_namespace'
-                               ]
-                       ],
-                       'join_conds' => [
-                               'page' => [
-                                       'LEFT JOIN',
-                                       [
-                                               'page_namespace = pl_namespace',
-                                               'page_title = pl_title'
-                                       ]
-                               ]
-                       ]
-               ];
-       }
-
-       /**
-        * Pre-fill the link cache
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * Make a link to "what links here" for the specified title
-        *
-        * @param Title $title Title being queried
-        * @param string $caption Text to display on the link
-        * @return string
-        */
-       function makeWlhLink( $title, $caption ) {
-               $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedDBkey() );
-
-               $linkRenderer = $this->getLinkRenderer();
-               return $linkRenderer->makeKnownLink( $wlh, $caption );
-       }
-
-       /**
-        * Make links to the page corresponding to the item,
-        * and the "what links here" page for it
-        *
-        * @param Skin $skin Skin to be used
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $title = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$title ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title )
-                       );
-               }
-
-               $linkRenderer = $this->getLinkRenderer();
-               $link = $linkRenderer->makeLink( $title );
-               $wlh = $this->makeWlhLink(
-                       $title,
-                       $this->msg( 'nlinks' )->numParams( $result->value )->text()
-               );
-
-               return $this->getLanguage()->specialList( $link, $wlh );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostlinkedcategories.php b/includes/specials/SpecialMostlinkedcategories.php
deleted file mode 100644 (file)
index 56a701a..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-/**
- * Implements Special:Mostlinkedcategories
- *
- * Copyright © 2005, Ævar Arnfjörð Bjarmason
- *
- * 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 SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * A querypage to show categories ordered in descending order by the pages in them
- *
- * @ingroup SpecialPage
- */
-class MostlinkedCategoriesPage extends QueryPage {
-       function __construct( $name = 'Mostlinkedcategories' ) {
-               parent::__construct( $name );
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'category' ],
-                       'fields' => [ 'title' => 'cat_title',
-                               'namespace' => NS_CATEGORY,
-                               'value' => 'cat_pages' ],
-                       'conds' => [ 'cat_pages > 0' ],
-               ];
-       }
-
-       function sortDescending() {
-               return true;
-       }
-
-       /**
-        * Fetch user page links and cache their existence
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $nt = Title::makeTitleSafe( NS_CATEGORY, $result->title );
-               if ( !$nt ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       NS_CATEGORY,
-                                       $result->title )
-                       );
-               }
-
-               $text = MediaWikiServices::getInstance()->getContentLanguage()
-                       ->convert( htmlspecialchars( $nt->getText() ) );
-               $plink = $this->getLinkRenderer()->makeLink( $nt, new HtmlArmor( $text ) );
-               $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped();
-
-               return $this->getLanguage()->specialList( $plink, $nlinks );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostlinkedtemplates.php b/includes/specials/SpecialMostlinkedtemplates.php
deleted file mode 100644 (file)
index 4544468..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-<?php
-/**
- * Implements Special:Mostlinkedtemplates
- *
- * 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 SpecialPage
- * @author Rob Church <robchur@gmail.com>
- */
-
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * Special page lists templates with a large number of
- * transclusion links, i.e. "most used" templates
- *
- * @ingroup SpecialPage
- */
-class MostlinkedTemplatesPage extends QueryPage {
-       function __construct( $name = 'Mostlinkedtemplates' ) {
-               parent::__construct( $name );
-       }
-
-       /**
-        * Is this report expensive, i.e should it be cached?
-        *
-        * @return bool
-        */
-       public function isExpensive() {
-               return true;
-       }
-
-       /**
-        * Is there a feed available?
-        *
-        * @return bool
-        */
-       public function isSyndicated() {
-               return false;
-       }
-
-       /**
-        * Sort the results in descending order?
-        *
-        * @return bool
-        */
-       public function sortDescending() {
-               return true;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'templatelinks' ],
-                       'fields' => [
-                               'namespace' => 'tl_namespace',
-                               'title' => 'tl_title',
-                               'value' => 'COUNT(*)'
-                       ],
-                       'options' => [ 'GROUP BY' => [ 'tl_namespace', 'tl_title' ] ]
-               ];
-       }
-
-       /**
-        * Pre-cache page existence to speed up link generation
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       public function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       /**
-        * Format a result row
-        *
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       public function formatResult( $skin, $result ) {
-               $title = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$title ) {
-                       return Html::element(
-                               'span',
-                               [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription(
-                                       $this->getContext(),
-                                       $result->namespace,
-                                       $result->title
-                               )
-                       );
-               }
-
-               return $this->getLanguage()->specialList(
-                       $this->getLinkRenderer()->makeLink( $title ),
-                       $this->makeWlhLink( $title, $result )
-               );
-       }
-
-       /**
-        * Make a "what links here" link for a given title
-        *
-        * @param Title $title Title to make the link for
-        * @param object $result Result row
-        * @return string
-        */
-       private function makeWlhLink( $title, $result ) {
-               $wlh = SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() );
-               $label = $this->msg( 'ntransclusions' )->numParams( $result->value )->text();
-
-               return $this->getLinkRenderer()->makeLink( $wlh, $label );
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialMostrevisions.php b/includes/specials/SpecialMostrevisions.php
deleted file mode 100644 (file)
index 0471caf..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/**
- * Implements Special:Mostrevisions
- *
- * Copyright © 2005 Ævar Arnfjörð Bjarmason
- *
- * 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 SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- */
-
-class MostrevisionsPage extends FewestrevisionsPage {
-       function __construct( $name = 'Mostrevisions' ) {
-               parent::__construct( $name );
-       }
-
-       function sortDescending() {
-               return true;
-       }
-
-       protected function getGroupName() {
-               return 'highuse';
-       }
-}
diff --git a/includes/specials/SpecialNewFiles.php b/includes/specials/SpecialNewFiles.php
new file mode 100644 (file)
index 0000000..29e7789
--- /dev/null
@@ -0,0 +1,226 @@
+<?php
+/**
+ * Implements Special:Newimages
+ *
+ * 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 SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+class SpecialNewFiles extends IncludableSpecialPage {
+       /** @var FormOptions */
+       protected $opts;
+
+       /** @var string[] */
+       protected $mediaTypes;
+
+       public function __construct() {
+               parent::__construct( 'Newimages' );
+       }
+
+       public function execute( $par ) {
+               $context = new DerivativeContext( $this->getContext() );
+
+               $this->setHeaders();
+               $this->outputHeader();
+               $mimeAnalyzer = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
+               $this->mediaTypes = $mimeAnalyzer->getMediaTypes();
+
+               $out = $this->getOutput();
+               $this->addHelpLink( 'Help:New images' );
+
+               $opts = new FormOptions();
+
+               $opts->add( 'like', '' );
+               $opts->add( 'user', '' );
+               $opts->add( 'showbots', false );
+               $opts->add( 'hidepatrolled', false );
+               $opts->add( 'mediatype', $this->mediaTypes );
+               $opts->add( 'limit', 50 );
+               $opts->add( 'offset', '' );
+               $opts->add( 'start', '' );
+               $opts->add( 'end', '' );
+
+               $opts->fetchValuesFromRequest( $this->getRequest() );
+
+               if ( $par !== null ) {
+                       $opts->setValue( is_numeric( $par ) ? 'limit' : 'like', $par );
+               }
+
+               // If start date comes after end date chronologically, swap them.
+               // They are swapped in the interface by JS.
+               $start = $opts->getValue( 'start' );
+               $end = $opts->getValue( 'end' );
+               if ( $start !== '' && $end !== '' && $start > $end ) {
+                       $temp = $end;
+                       $end = $start;
+                       $start = $temp;
+
+                       $opts->setValue( 'start', $start, true );
+                       $opts->setValue( 'end', $end, true );
+
+                       // also swap values in request object, which is used by HTMLForm
+                       // to pre-populate the fields with the previous input
+                       $request = $context->getRequest();
+                       $context->setRequest( new DerivativeRequest(
+                               $request,
+                               [ 'start' => $start, 'end' => $end ] + $request->getValues(),
+                               $request->wasPosted()
+                       ) );
+               }
+
+               // if all media types have been selected, wipe out the array to prevent
+               // the pointless IN(...) query condition (which would have no effect
+               // because every possible type has been selected)
+               $missingMediaTypes = array_diff( $this->mediaTypes, $opts->getValue( 'mediatype' ) );
+               if ( empty( $missingMediaTypes ) ) {
+                       $opts->setValue( 'mediatype', [] );
+               }
+
+               $opts->validateIntBounds( 'limit', 0, 500 );
+
+               $this->opts = $opts;
+
+               if ( !$this->including() ) {
+                       $this->setTopText();
+                       $this->buildForm( $context );
+               }
+
+               $pager = new NewFilesPager( $context, $opts, $this->getLinkRenderer() );
+
+               $out->addHTML( $pager->getBody() );
+               if ( !$this->including() ) {
+                       $out->addHTML( $pager->getNavigationBar() );
+               }
+       }
+
+       protected function buildForm( IContextSource $context ) {
+               $mediaTypesText = array_map( function ( $type ) {
+                       // mediastatistics-header-unknown, mediastatistics-header-bitmap,
+                       // mediastatistics-header-drawing, mediastatistics-header-audio,
+                       // mediastatistics-header-video, mediastatistics-header-multimedia,
+                       // mediastatistics-header-office, mediastatistics-header-text,
+                       // mediastatistics-header-executable, mediastatistics-header-archive,
+                       // mediastatistics-header-3d,
+                       return $this->msg( 'mediastatistics-header-' . strtolower( $type ) )->text();
+               }, $this->mediaTypes );
+               $mediaTypesOptions = array_combine( $mediaTypesText, $this->mediaTypes );
+               ksort( $mediaTypesOptions );
+
+               $formDescriptor = [
+                       'like' => [
+                               'type' => 'text',
+                               'label-message' => 'newimages-label',
+                               'name' => 'like',
+                       ],
+
+                       'user' => [
+                               'class' => 'HTMLUserTextField',
+                               'label-message' => 'newimages-user',
+                               'name' => 'user',
+                       ],
+
+                       'showbots' => [
+                               'type' => 'check',
+                               'label-message' => 'newimages-showbots',
+                               'name' => 'showbots',
+                       ],
+
+                       'hidepatrolled' => [
+                               'type' => 'check',
+                               'label-message' => 'newimages-hidepatrolled',
+                               'name' => 'hidepatrolled',
+                       ],
+
+                       'mediatype' => [
+                               'type' => 'multiselect',
+                               'flatlist' => true,
+                               'name' => 'mediatype',
+                               'label-message' => 'newimages-mediatype',
+                               'options' => $mediaTypesOptions,
+                               'default' => $this->mediaTypes,
+                       ],
+
+                       'limit' => [
+                               'type' => 'hidden',
+                               'default' => $this->opts->getValue( 'limit' ),
+                               'name' => 'limit',
+                       ],
+
+                       'offset' => [
+                               'type' => 'hidden',
+                               'default' => $this->opts->getValue( 'offset' ),
+                               'name' => 'offset',
+                       ],
+
+                       'start' => [
+                               'type' => 'date',
+                               'label-message' => 'date-range-from',
+                               'name' => 'start',
+                       ],
+
+                       'end' => [
+                               'type' => 'date',
+                               'label-message' => 'date-range-to',
+                               'name' => 'end',
+                       ],
+               ];
+
+               if ( $this->getConfig()->get( 'MiserMode' ) ) {
+                       unset( $formDescriptor['like'] );
+               }
+
+               if ( !$this->getUser()->useFilePatrol() ) {
+                       unset( $formDescriptor['hidepatrolled'] );
+               }
+
+               HTMLForm::factory( 'ooui', $formDescriptor, $context )
+                       // For the 'multiselect' field values to be preserved on submit
+                       ->setFormIdentifier( 'specialnewimages' )
+                       ->setWrapperLegendMsg( 'newimages-legend' )
+                       ->setSubmitTextMsg( 'ilsubmit' )
+                       ->setMethod( 'get' )
+                       ->prepareForm()
+                       ->displayForm( false );
+       }
+
+       protected function getGroupName() {
+               return 'changes';
+       }
+
+       /**
+        * Send the text to be displayed above the options
+        */
+       function setTopText() {
+               $message = $this->msg( 'newimagestext' )->inContentLanguage();
+               if ( !$message->isDisabled() ) {
+                       $contLang = MediaWikiServices::getInstance()->getContentLanguage();
+                       $this->getOutput()->addWikiTextAsContent(
+                               Html::rawElement( 'div',
+                                       [
+
+                                               'lang' => $contLang->getHtmlCode(),
+                                               'dir' => $contLang->getDir()
+                                       ],
+                                       "\n" . $message->plain() . "\n"
+                               )
+                       );
+               }
+       }
+}
diff --git a/includes/specials/SpecialNewimages.php b/includes/specials/SpecialNewimages.php
deleted file mode 100644 (file)
index 29e7789..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-<?php
-/**
- * Implements Special:Newimages
- *
- * 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 SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-class SpecialNewFiles extends IncludableSpecialPage {
-       /** @var FormOptions */
-       protected $opts;
-
-       /** @var string[] */
-       protected $mediaTypes;
-
-       public function __construct() {
-               parent::__construct( 'Newimages' );
-       }
-
-       public function execute( $par ) {
-               $context = new DerivativeContext( $this->getContext() );
-
-               $this->setHeaders();
-               $this->outputHeader();
-               $mimeAnalyzer = MediaWiki\MediaWikiServices::getInstance()->getMimeAnalyzer();
-               $this->mediaTypes = $mimeAnalyzer->getMediaTypes();
-
-               $out = $this->getOutput();
-               $this->addHelpLink( 'Help:New images' );
-
-               $opts = new FormOptions();
-
-               $opts->add( 'like', '' );
-               $opts->add( 'user', '' );
-               $opts->add( 'showbots', false );
-               $opts->add( 'hidepatrolled', false );
-               $opts->add( 'mediatype', $this->mediaTypes );
-               $opts->add( 'limit', 50 );
-               $opts->add( 'offset', '' );
-               $opts->add( 'start', '' );
-               $opts->add( 'end', '' );
-
-               $opts->fetchValuesFromRequest( $this->getRequest() );
-
-               if ( $par !== null ) {
-                       $opts->setValue( is_numeric( $par ) ? 'limit' : 'like', $par );
-               }
-
-               // If start date comes after end date chronologically, swap them.
-               // They are swapped in the interface by JS.
-               $start = $opts->getValue( 'start' );
-               $end = $opts->getValue( 'end' );
-               if ( $start !== '' && $end !== '' && $start > $end ) {
-                       $temp = $end;
-                       $end = $start;
-                       $start = $temp;
-
-                       $opts->setValue( 'start', $start, true );
-                       $opts->setValue( 'end', $end, true );
-
-                       // also swap values in request object, which is used by HTMLForm
-                       // to pre-populate the fields with the previous input
-                       $request = $context->getRequest();
-                       $context->setRequest( new DerivativeRequest(
-                               $request,
-                               [ 'start' => $start, 'end' => $end ] + $request->getValues(),
-                               $request->wasPosted()
-                       ) );
-               }
-
-               // if all media types have been selected, wipe out the array to prevent
-               // the pointless IN(...) query condition (which would have no effect
-               // because every possible type has been selected)
-               $missingMediaTypes = array_diff( $this->mediaTypes, $opts->getValue( 'mediatype' ) );
-               if ( empty( $missingMediaTypes ) ) {
-                       $opts->setValue( 'mediatype', [] );
-               }
-
-               $opts->validateIntBounds( 'limit', 0, 500 );
-
-               $this->opts = $opts;
-
-               if ( !$this->including() ) {
-                       $this->setTopText();
-                       $this->buildForm( $context );
-               }
-
-               $pager = new NewFilesPager( $context, $opts, $this->getLinkRenderer() );
-
-               $out->addHTML( $pager->getBody() );
-               if ( !$this->including() ) {
-                       $out->addHTML( $pager->getNavigationBar() );
-               }
-       }
-
-       protected function buildForm( IContextSource $context ) {
-               $mediaTypesText = array_map( function ( $type ) {
-                       // mediastatistics-header-unknown, mediastatistics-header-bitmap,
-                       // mediastatistics-header-drawing, mediastatistics-header-audio,
-                       // mediastatistics-header-video, mediastatistics-header-multimedia,
-                       // mediastatistics-header-office, mediastatistics-header-text,
-                       // mediastatistics-header-executable, mediastatistics-header-archive,
-                       // mediastatistics-header-3d,
-                       return $this->msg( 'mediastatistics-header-' . strtolower( $type ) )->text();
-               }, $this->mediaTypes );
-               $mediaTypesOptions = array_combine( $mediaTypesText, $this->mediaTypes );
-               ksort( $mediaTypesOptions );
-
-               $formDescriptor = [
-                       'like' => [
-                               'type' => 'text',
-                               'label-message' => 'newimages-label',
-                               'name' => 'like',
-                       ],
-
-                       'user' => [
-                               'class' => 'HTMLUserTextField',
-                               'label-message' => 'newimages-user',
-                               'name' => 'user',
-                       ],
-
-                       'showbots' => [
-                               'type' => 'check',
-                               'label-message' => 'newimages-showbots',
-                               'name' => 'showbots',
-                       ],
-
-                       'hidepatrolled' => [
-                               'type' => 'check',
-                               'label-message' => 'newimages-hidepatrolled',
-                               'name' => 'hidepatrolled',
-                       ],
-
-                       'mediatype' => [
-                               'type' => 'multiselect',
-                               'flatlist' => true,
-                               'name' => 'mediatype',
-                               'label-message' => 'newimages-mediatype',
-                               'options' => $mediaTypesOptions,
-                               'default' => $this->mediaTypes,
-                       ],
-
-                       'limit' => [
-                               'type' => 'hidden',
-                               'default' => $this->opts->getValue( 'limit' ),
-                               'name' => 'limit',
-                       ],
-
-                       'offset' => [
-                               'type' => 'hidden',
-                               'default' => $this->opts->getValue( 'offset' ),
-                               'name' => 'offset',
-                       ],
-
-                       'start' => [
-                               'type' => 'date',
-                               'label-message' => 'date-range-from',
-                               'name' => 'start',
-                       ],
-
-                       'end' => [
-                               'type' => 'date',
-                               'label-message' => 'date-range-to',
-                               'name' => 'end',
-                       ],
-               ];
-
-               if ( $this->getConfig()->get( 'MiserMode' ) ) {
-                       unset( $formDescriptor['like'] );
-               }
-
-               if ( !$this->getUser()->useFilePatrol() ) {
-                       unset( $formDescriptor['hidepatrolled'] );
-               }
-
-               HTMLForm::factory( 'ooui', $formDescriptor, $context )
-                       // For the 'multiselect' field values to be preserved on submit
-                       ->setFormIdentifier( 'specialnewimages' )
-                       ->setWrapperLegendMsg( 'newimages-legend' )
-                       ->setSubmitTextMsg( 'ilsubmit' )
-                       ->setMethod( 'get' )
-                       ->prepareForm()
-                       ->displayForm( false );
-       }
-
-       protected function getGroupName() {
-               return 'changes';
-       }
-
-       /**
-        * Send the text to be displayed above the options
-        */
-       function setTopText() {
-               $message = $this->msg( 'newimagestext' )->inContentLanguage();
-               if ( !$message->isDisabled() ) {
-                       $contLang = MediaWikiServices::getInstance()->getContentLanguage();
-                       $this->getOutput()->addWikiTextAsContent(
-                               Html::rawElement( 'div',
-                                       [
-
-                                               'lang' => $contLang->getHtmlCode(),
-                                               'dir' => $contLang->getDir()
-                                       ],
-                                       "\n" . $message->plain() . "\n"
-                               )
-                       );
-               }
-       }
-}
diff --git a/includes/specials/SpecialShortPages.php b/includes/specials/SpecialShortPages.php
new file mode 100644 (file)
index 0000000..f1bd065
--- /dev/null
@@ -0,0 +1,182 @@
+<?php
+/**
+ * Implements Special:Shortpages
+ *
+ * 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 SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * SpecialShortpages extends QueryPage. It is used to return the shortest
+ * pages in the database.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialShortPages extends QueryPage {
+
+       function __construct( $name = 'Shortpages' ) {
+               parent::__construct( $name );
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               $config = $this->getConfig();
+               $blacklist = $config->get( 'ShortPagesNamespaceBlacklist' );
+               $tables = [ 'page' ];
+               $conds = [
+                       'page_namespace' => array_diff(
+                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces(),
+                               $blacklist
+                       ),
+                       'page_is_redirect' => 0
+               ];
+               $joinConds = [];
+               $options = [ 'USE INDEX' => [ 'page' => 'page_redirect_namespace_len' ] ];
+
+               // Allow extensions to modify the query
+               Hooks::run( 'ShortPagesQuery', [ &$tables, &$conds, &$joinConds, &$options ] );
+
+               return [
+                       'tables' => $tables,
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_len'
+                       ],
+                       'conds' => $conds,
+                       'join_conds' => $joinConds,
+                       'options' => $options
+               ];
+       }
+
+       public function reallyDoQuery( $limit, $offset = false ) {
+               $fname = static::class . '::reallyDoQuery';
+               $dbr = $this->getRecacheDB();
+               $query = $this->getQueryInfo();
+               $order = $this->getOrderFields();
+
+               if ( $this->sortDescending() ) {
+                       foreach ( $order as &$field ) {
+                               $field .= ' DESC';
+                       }
+               }
+
+               $tables = isset( $query['tables'] ) ? (array)$query['tables'] : [];
+               $fields = isset( $query['fields'] ) ? (array)$query['fields'] : [];
+               $conds = isset( $query['conds'] ) ? (array)$query['conds'] : [];
+               $options = isset( $query['options'] ) ? (array)$query['options'] : [];
+               $join_conds = isset( $query['join_conds'] ) ? (array)$query['join_conds'] : [];
+
+               if ( $limit !== false ) {
+                       $options['LIMIT'] = intval( $limit );
+               }
+
+               if ( $offset !== false ) {
+                       $options['OFFSET'] = intval( $offset );
+               }
+
+               $namespaces = $conds['page_namespace'];
+               if ( count( $namespaces ) === 1 ) {
+                       $options['ORDER BY'] = $order;
+                       $res = $dbr->select( $tables, $fields, $conds, $fname,
+                               $options, $join_conds
+                       );
+               } else {
+                       unset( $conds['page_namespace'] );
+                       $options['INNER ORDER BY'] = $order;
+                       $options['ORDER BY'] = [ 'value' . ( $this->sortDescending() ? ' DESC' : '' ) ];
+                       $sql = $dbr->unionConditionPermutations(
+                               $tables,
+                               $fields,
+                               [ 'page_namespace' => $namespaces ],
+                               $conds,
+                               $fname,
+                               $options,
+                               $join_conds
+                       );
+                       $res = $dbr->query( $sql, $fname );
+               }
+
+               return $res;
+       }
+
+       function getOrderFields() {
+               return [ 'page_len' ];
+       }
+
+       /**
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $dm = $this->getLanguage()->getDirMark();
+
+               $title = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$title ) {
+                       return Html::element( 'span', [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) );
+               }
+
+               $linkRenderer = $this->getLinkRenderer();
+               $hlink = $linkRenderer->makeKnownLink(
+                       $title,
+                       $this->msg( 'hist' )->text(),
+                       [],
+                       [ 'action' => 'history' ]
+               );
+               $hlinkInParentheses = $this->msg( 'parentheses' )->rawParams( $hlink )->escaped();
+
+               if ( $this->isCached() ) {
+                       $plink = $linkRenderer->makeLink( $title );
+                       $exists = $title->exists();
+               } else {
+                       $plink = $linkRenderer->makeKnownLink( $title );
+                       $exists = true;
+               }
+
+               $size = $this->msg( 'nbytes' )->numParams( $result->value )->escaped();
+
+               return $exists
+                       ? "${hlinkInParentheses} {$dm}{$plink} {$dm}[{$size}]"
+                       : "<del>${hlinkInParentheses} {$dm}{$plink} {$dm}[{$size}]</del>";
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialShortpages.php b/includes/specials/SpecialShortpages.php
deleted file mode 100644 (file)
index 94da25d..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-<?php
-/**
- * Implements Special:Shortpages
- *
- * 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 SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * SpecialShortpages extends QueryPage. It is used to return the shortest
- * pages in the database.
- *
- * @ingroup SpecialPage
- */
-class ShortPagesPage extends QueryPage {
-
-       function __construct( $name = 'Shortpages' ) {
-               parent::__construct( $name );
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               $config = $this->getConfig();
-               $blacklist = $config->get( 'ShortPagesNamespaceBlacklist' );
-               $tables = [ 'page' ];
-               $conds = [
-                       'page_namespace' => array_diff(
-                               MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces(),
-                               $blacklist
-                       ),
-                       'page_is_redirect' => 0
-               ];
-               $joinConds = [];
-               $options = [ 'USE INDEX' => [ 'page' => 'page_redirect_namespace_len' ] ];
-
-               // Allow extensions to modify the query
-               Hooks::run( 'ShortPagesQuery', [ &$tables, &$conds, &$joinConds, &$options ] );
-
-               return [
-                       'tables' => $tables,
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_len'
-                       ],
-                       'conds' => $conds,
-                       'join_conds' => $joinConds,
-                       'options' => $options
-               ];
-       }
-
-       public function reallyDoQuery( $limit, $offset = false ) {
-               $fname = static::class . '::reallyDoQuery';
-               $dbr = $this->getRecacheDB();
-               $query = $this->getQueryInfo();
-               $order = $this->getOrderFields();
-
-               if ( $this->sortDescending() ) {
-                       foreach ( $order as &$field ) {
-                               $field .= ' DESC';
-                       }
-               }
-
-               $tables = isset( $query['tables'] ) ? (array)$query['tables'] : [];
-               $fields = isset( $query['fields'] ) ? (array)$query['fields'] : [];
-               $conds = isset( $query['conds'] ) ? (array)$query['conds'] : [];
-               $options = isset( $query['options'] ) ? (array)$query['options'] : [];
-               $join_conds = isset( $query['join_conds'] ) ? (array)$query['join_conds'] : [];
-
-               if ( $limit !== false ) {
-                       $options['LIMIT'] = intval( $limit );
-               }
-
-               if ( $offset !== false ) {
-                       $options['OFFSET'] = intval( $offset );
-               }
-
-               $namespaces = $conds['page_namespace'];
-               if ( count( $namespaces ) === 1 ) {
-                       $options['ORDER BY'] = $order;
-                       $res = $dbr->select( $tables, $fields, $conds, $fname,
-                               $options, $join_conds
-                       );
-               } else {
-                       unset( $conds['page_namespace'] );
-                       $options['INNER ORDER BY'] = $order;
-                       $options['ORDER BY'] = [ 'value' . ( $this->sortDescending() ? ' DESC' : '' ) ];
-                       $sql = $dbr->unionConditionPermutations(
-                               $tables,
-                               $fields,
-                               [ 'page_namespace' => $namespaces ],
-                               $conds,
-                               $fname,
-                               $options,
-                               $join_conds
-                       );
-                       $res = $dbr->query( $sql, $fname );
-               }
-
-               return $res;
-       }
-
-       function getOrderFields() {
-               return [ 'page_len' ];
-       }
-
-       /**
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $dm = $this->getLanguage()->getDirMark();
-
-               $title = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$title ) {
-                       return Html::element( 'span', [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) );
-               }
-
-               $linkRenderer = $this->getLinkRenderer();
-               $hlink = $linkRenderer->makeKnownLink(
-                       $title,
-                       $this->msg( 'hist' )->text(),
-                       [],
-                       [ 'action' => 'history' ]
-               );
-               $hlinkInParentheses = $this->msg( 'parentheses' )->rawParams( $hlink )->escaped();
-
-               if ( $this->isCached() ) {
-                       $plink = $linkRenderer->makeLink( $title );
-                       $exists = $title->exists();
-               } else {
-                       $plink = $linkRenderer->makeKnownLink( $title );
-                       $exists = true;
-               }
-
-               $size = $this->msg( 'nbytes' )->numParams( $result->value )->escaped();
-
-               return $exists
-                       ? "${hlinkInParentheses} {$dm}{$plink} {$dm}[{$size}]"
-                       : "<del>${hlinkInParentheses} {$dm}{$plink} {$dm}[{$size}]</del>";
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialUncategorizedCategories.php b/includes/specials/SpecialUncategorizedCategories.php
new file mode 100644 (file)
index 0000000..7349d95
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Implements Special:Uncategorizedcategories
+ *
+ * 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 SpecialPage
+ */
+
+/**
+ * A special page that lists uncategorized categories
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialUncategorizedCategories extends SpecialUncategorizedPages {
+       /**
+        * Holds a list of categories, which shouldn't be listed on this special page,
+        * even if it is uncategorized.
+        * @var array
+        */
+       private $exceptionList = null;
+
+       function __construct( $name = 'Uncategorizedcategories' ) {
+               parent::__construct( $name );
+               $this->requestedNamespace = NS_CATEGORY;
+       }
+
+       /**
+        * Returns an array of category titles (usually without the namespace), which
+        * shouldn't be listed on this page, even if they're uncategorized.
+        *
+        * @return array
+        */
+       private function getExceptionList() {
+               if ( $this->exceptionList === null ) {
+                       $this->exceptionList = [];
+                       $exList = $this->msg( 'uncategorized-categories-exceptionlist' )
+                               ->inContentLanguage()->plain();
+                       $proposedTitles = explode( "\n", $exList );
+                       foreach ( $proposedTitles as $count => $titleStr ) {
+                               if ( strpos( $titleStr, '*' ) !== 0 ) {
+                                       continue;
+                               }
+                               $titleStr = preg_replace( "/^\\*\\s*/", '', $titleStr );
+                               $title = Title::newFromText( $titleStr, NS_CATEGORY );
+                               if ( $title && $title->getNamespace() !== NS_CATEGORY ) {
+                                       $title = Title::makeTitleSafe( NS_CATEGORY, $titleStr );
+                               }
+                               if ( $title ) {
+                                       $this->exceptionList[] = $title->getDBkey();
+                               }
+                       }
+               }
+               return $this->exceptionList;
+       }
+
+       public function getQueryInfo() {
+               $dbr = wfGetDB( DB_REPLICA );
+               $query = parent::getQueryInfo();
+               $exceptionList = $this->getExceptionList();
+               if ( $exceptionList ) {
+                       $query['conds'][] = 'page_title not in ( ' . $dbr->makeList( $exceptionList ) . ' )';
+               }
+
+               return $query;
+       }
+
+       /**
+        * Formats the result
+        * @param Skin $skin The current skin
+        * @param object $result The query result
+        * @return string The category link
+        */
+       function formatResult( $skin, $result ) {
+               $title = Title::makeTitle( NS_CATEGORY, $result->title );
+               $text = $title->getText();
+
+               return $this->getLinkRenderer()->makeKnownLink( $title, $text );
+       }
+}
diff --git a/includes/specials/SpecialUncategorizedImages.php b/includes/specials/SpecialUncategorizedImages.php
new file mode 100644 (file)
index 0000000..9dcd1bd
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Implements Special:Uncategorizedimages
+ *
+ * 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 SpecialPage
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+/**
+ * Special page lists images which haven't been categorised
+ *
+ * @ingroup SpecialPage
+ * @todo FIXME: Use an instance of UncategorizedPagesPage or something
+ */
+class SpecialUncategorizedImages extends ImageQueryPage {
+       function __construct( $name = 'Uncategorizedimages' ) {
+               parent::__construct( $name );
+               $this->addHelpLink( 'Help:Categories' );
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function getQueryInfo() {
+               return [
+                       'tables' => [ 'page', 'categorylinks' ],
+                       'fields' => [ 'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title' ],
+                       'conds' => [ 'cl_from IS NULL',
+                               'page_namespace' => NS_FILE,
+                               'page_is_redirect' => 0 ],
+                       'join_conds' => [ 'categorylinks' => [
+                               'LEFT JOIN', 'cl_from=page_id' ] ]
+               ];
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialUncategorizedPages.php b/includes/specials/SpecialUncategorizedPages.php
new file mode 100644 (file)
index 0000000..3610c01
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Implements Special:Uncategorizedpages
+ *
+ * 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 SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * A special page looking for page without any category.
+ *
+ * @ingroup SpecialPage
+ * @todo FIXME: Make $requestedNamespace selectable, unify all subclasses into one
+ */
+class SpecialUncategorizedPages extends PageQueryPage {
+       /** @var int|false */
+       protected $requestedNamespace = false;
+
+       function __construct( $name = 'Uncategorizedpages' ) {
+               parent::__construct( $name );
+               $this->addHelpLink( 'Help:Categories' );
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function getQueryInfo() {
+               return [
+                       'tables' => [ 'page', 'categorylinks' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title'
+                       ],
+                       // default for page_namespace is all content namespaces (if requestedNamespace is false)
+                       // otherwise, page_namespace is requestedNamespace
+                       'conds' => [
+                               'cl_from IS NULL',
+                               'page_namespace' => $this->requestedNamespace !== false
+                                               ? $this->requestedNamespace
+                                               : MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                                       getContentNamespaces(),
+                               'page_is_redirect' => 0
+                       ],
+                       'join_conds' => [
+                               'categorylinks' => [ 'LEFT JOIN', 'cl_from = page_id' ]
+                       ]
+               ];
+       }
+
+       function getOrderFields() {
+               // For some crazy reason ordering by a constant
+               // causes a filesort
+               if ( $this->requestedNamespace === false &&
+                       count( MediaWikiServices::getInstance()->getNamespaceInfo()->
+                               getContentNamespaces() ) > 1
+               ) {
+                       return [ 'page_namespace', 'page_title' ];
+               }
+
+               return [ 'page_title' ];
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialUncategorizedTemplates.php b/includes/specials/SpecialUncategorizedTemplates.php
new file mode 100644 (file)
index 0000000..3d6d383
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Implements Special:Uncategorizedtemplates
+ *
+ * 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 SpecialPage
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+/**
+ * Special page lists all uncategorised pages in the
+ * template namespace
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialUncategorizedTemplates extends SpecialUncategorizedPages {
+       public function __construct( $name = 'Uncategorizedtemplates' ) {
+               parent::__construct( $name );
+               $this->requestedNamespace = NS_TEMPLATE;
+       }
+}
diff --git a/includes/specials/SpecialUncategorizedcategories.php b/includes/specials/SpecialUncategorizedcategories.php
deleted file mode 100644 (file)
index 60cbff1..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-<?php
-/**
- * Implements Special:Uncategorizedcategories
- *
- * 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 SpecialPage
- */
-
-/**
- * A special page that lists uncategorized categories
- *
- * @ingroup SpecialPage
- */
-class UncategorizedCategoriesPage extends UncategorizedPagesPage {
-       /**
-        * Holds a list of categories, which shouldn't be listed on this special page,
-        * even if it is uncategorized.
-        * @var array
-        */
-       private $exceptionList = null;
-
-       function __construct( $name = 'Uncategorizedcategories' ) {
-               parent::__construct( $name );
-               $this->requestedNamespace = NS_CATEGORY;
-       }
-
-       /**
-        * Returns an array of category titles (usually without the namespace), which
-        * shouldn't be listed on this page, even if they're uncategorized.
-        *
-        * @return array
-        */
-       private function getExceptionList() {
-               if ( $this->exceptionList === null ) {
-                       $this->exceptionList = [];
-                       $exList = $this->msg( 'uncategorized-categories-exceptionlist' )
-                               ->inContentLanguage()->plain();
-                       $proposedTitles = explode( "\n", $exList );
-                       foreach ( $proposedTitles as $count => $titleStr ) {
-                               if ( strpos( $titleStr, '*' ) !== 0 ) {
-                                       continue;
-                               }
-                               $titleStr = preg_replace( "/^\\*\\s*/", '', $titleStr );
-                               $title = Title::newFromText( $titleStr, NS_CATEGORY );
-                               if ( $title && $title->getNamespace() !== NS_CATEGORY ) {
-                                       $title = Title::makeTitleSafe( NS_CATEGORY, $titleStr );
-                               }
-                               if ( $title ) {
-                                       $this->exceptionList[] = $title->getDBkey();
-                               }
-                       }
-               }
-               return $this->exceptionList;
-       }
-
-       public function getQueryInfo() {
-               $dbr = wfGetDB( DB_REPLICA );
-               $query = parent::getQueryInfo();
-               $exceptionList = $this->getExceptionList();
-               if ( $exceptionList ) {
-                       $query['conds'][] = 'page_title not in ( ' . $dbr->makeList( $exceptionList ) . ' )';
-               }
-
-               return $query;
-       }
-
-       /**
-        * Formats the result
-        * @param Skin $skin The current skin
-        * @param object $result The query result
-        * @return string The category link
-        */
-       function formatResult( $skin, $result ) {
-               $title = Title::makeTitle( NS_CATEGORY, $result->title );
-               $text = $title->getText();
-
-               return $this->getLinkRenderer()->makeKnownLink( $title, $text );
-       }
-}
diff --git a/includes/specials/SpecialUncategorizedimages.php b/includes/specials/SpecialUncategorizedimages.php
deleted file mode 100644 (file)
index ed2d5cf..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-/**
- * Implements Special:Uncategorizedimages
- *
- * 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 SpecialPage
- * @author Rob Church <robchur@gmail.com>
- */
-
-/**
- * Special page lists images which haven't been categorised
- *
- * @ingroup SpecialPage
- * @todo FIXME: Use an instance of UncategorizedPagesPage or something
- */
-class UncategorizedImagesPage extends ImageQueryPage {
-       function __construct( $name = 'Uncategorizedimages' ) {
-               parent::__construct( $name );
-               $this->addHelpLink( 'Help:Categories' );
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function getQueryInfo() {
-               return [
-                       'tables' => [ 'page', 'categorylinks' ],
-                       'fields' => [ 'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title' ],
-                       'conds' => [ 'cl_from IS NULL',
-                               'page_namespace' => NS_FILE,
-                               'page_is_redirect' => 0 ],
-                       'join_conds' => [ 'categorylinks' => [
-                               'LEFT JOIN', 'cl_from=page_id' ] ]
-               ];
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialUncategorizedpages.php b/includes/specials/SpecialUncategorizedpages.php
deleted file mode 100644 (file)
index 0b7da7b..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-/**
- * Implements Special:Uncategorizedpages
- *
- * 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 SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * A special page looking for page without any category.
- *
- * @ingroup SpecialPage
- * @todo FIXME: Make $requestedNamespace selectable, unify all subclasses into one
- */
-class UncategorizedPagesPage extends PageQueryPage {
-       /** @var int|false */
-       protected $requestedNamespace = false;
-
-       function __construct( $name = 'Uncategorizedpages' ) {
-               parent::__construct( $name );
-               $this->addHelpLink( 'Help:Categories' );
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function getQueryInfo() {
-               return [
-                       'tables' => [ 'page', 'categorylinks' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title'
-                       ],
-                       // default for page_namespace is all content namespaces (if requestedNamespace is false)
-                       // otherwise, page_namespace is requestedNamespace
-                       'conds' => [
-                               'cl_from IS NULL',
-                               'page_namespace' => $this->requestedNamespace !== false
-                                               ? $this->requestedNamespace
-                                               : MediaWikiServices::getInstance()->getNamespaceInfo()->
-                                                       getContentNamespaces(),
-                               'page_is_redirect' => 0
-                       ],
-                       'join_conds' => [
-                               'categorylinks' => [ 'LEFT JOIN', 'cl_from = page_id' ]
-                       ]
-               ];
-       }
-
-       function getOrderFields() {
-               // For some crazy reason ordering by a constant
-               // causes a filesort
-               if ( $this->requestedNamespace === false &&
-                       count( MediaWikiServices::getInstance()->getNamespaceInfo()->
-                               getContentNamespaces() ) > 1
-               ) {
-                       return [ 'page_namespace', 'page_title' ];
-               }
-
-               return [ 'page_title' ];
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialUncategorizedtemplates.php b/includes/specials/SpecialUncategorizedtemplates.php
deleted file mode 100644 (file)
index af038fa..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-/**
- * Implements Special:Uncategorizedtemplates
- *
- * 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 SpecialPage
- * @author Rob Church <robchur@gmail.com>
- */
-
-/**
- * Special page lists all uncategorised pages in the
- * template namespace
- *
- * @ingroup SpecialPage
- */
-class UncategorizedTemplatesPage extends UncategorizedPagesPage {
-       public function __construct( $name = 'Uncategorizedtemplates' ) {
-               parent::__construct( $name );
-               $this->requestedNamespace = NS_TEMPLATE;
-       }
-}
index 075b5df..fe629db 100644 (file)
@@ -33,18 +33,28 @@ use Wikimedia\Rdbms\IResultWrapper;
  * @ingroup SpecialPage
  */
 class SpecialUndelete extends SpecialPage {
-       private $mAction;
-       private $mTarget;
-       private $mTimestamp;
-       private $mRestore;
-       private $mRevdel;
-       private $mInvert;
-       private $mFilename;
-       private $mTargetTimestamp;
-       private $mAllowed;
-       private $mCanView;
-       private $mComment;
-       private $mToken;
+       private $mAction;
+       private $mTarget;
+       private $mTimestamp;
+       private $mRestore;
+       private $mRevdel;
+       private $mInvert;
+       private $mFilename;
+       private $mTargetTimestamp;
+       private $mAllowed;
+       private $mCanView;
+       private $mComment;
+       private $mToken;
+       /** @var bool|null */
+       private $mPreview;
+       /** @var bool|null */
+       private $mDiff;
+       /** @var bool|null */
+       private $mDiffOnly;
+       /** @var bool|null */
+       private $mUnsuppress;
+       /** @var int[]|null */
+       private $mFileVersions;
 
        /** @var Title */
        private $mTargetObj;
diff --git a/includes/specials/SpecialUnusedCategories.php b/includes/specials/SpecialUnusedCategories.php
new file mode 100644 (file)
index 0000000..36367d2
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Implements Special:Unusedcategories
+ *
+ * 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 SpecialPage
+ */
+
+/**
+ * @ingroup SpecialPage
+ */
+class SpecialUnusedCategories extends QueryPage {
+       function __construct( $name = 'Unusedcategories' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function getPageHeader() {
+               return $this->msg( 'unusedcategoriestext' )->parseAsBlock();
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'page', 'categorylinks', 'page_props' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title'
+                       ],
+                       'conds' => [
+                               'cl_from IS NULL',
+                               'page_namespace' => NS_CATEGORY,
+                               'page_is_redirect' => 0,
+                               'pp_page IS NULL'
+                       ],
+                       'join_conds' => [
+                               'categorylinks' => [ 'LEFT JOIN', 'cl_to = page_title' ],
+                               'page_props' => [ 'LEFT JOIN', [
+                                       'page_id = pp_page',
+                                       'pp_propname' => 'expectunusedcategory'
+                               ] ]
+                       ]
+               ];
+       }
+
+       /**
+        * A should come before Z (T32907)
+        * @return bool
+        */
+       function sortDescending() {
+               return false;
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $title = Title::makeTitle( NS_CATEGORY, $result->title );
+
+               return $this->getLinkRenderer()->makeLink( $title, $title->getText() );
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+
+       public function preprocessResults( $db, $res ) {
+               $this->executeLBFromResultWrapper( $res );
+       }
+}
diff --git a/includes/specials/SpecialUnusedImages.php b/includes/specials/SpecialUnusedImages.php
new file mode 100644 (file)
index 0000000..cb215e3
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Implements Special:Unusedimages
+ *
+ * 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 SpecialPage
+ */
+
+/**
+ * A special page that lists unused images
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialUnusedImages extends ImageQueryPage {
+       function __construct( $name = 'Unusedimages' ) {
+               parent::__construct( $name );
+       }
+
+       function isExpensive() {
+               return true;
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function getQueryInfo() {
+               $retval = [
+                       'tables' => [ 'image', 'imagelinks' ],
+                       'fields' => [
+                               'namespace' => NS_FILE,
+                               'title' => 'img_name',
+                               'value' => 'img_timestamp',
+                       ],
+                       'conds' => [ 'il_to IS NULL' ],
+                       'join_conds' => [ 'imagelinks' => [ 'LEFT JOIN', 'il_to = img_name' ] ]
+               ];
+
+               if ( $this->getConfig()->get( 'CountCategorizedImagesAsUsed' ) ) {
+                       // Order is significant
+                       $retval['tables'] = [ 'image', 'page', 'categorylinks',
+                               'imagelinks' ];
+                       $retval['conds']['page_namespace'] = NS_FILE;
+                       $retval['conds'][] = 'cl_from IS NULL';
+                       $retval['conds'][] = 'img_name = page_title';
+                       $retval['join_conds']['categorylinks'] = [
+                               'LEFT JOIN', 'cl_from = page_id' ];
+                       $retval['join_conds']['imagelinks'] = [
+                               'LEFT JOIN', 'il_to = page_title' ];
+               }
+
+               return $retval;
+       }
+
+       function usesTimestamps() {
+               return true;
+       }
+
+       function getPageHeader() {
+               if ( $this->getConfig()->get( 'CountCategorizedImagesAsUsed' ) ) {
+                       return $this->msg(
+                               'unusedimagestext-categorizedimgisused'
+                       )->parseAsBlock();
+               }
+               return $this->msg( 'unusedimagestext' )->parseAsBlock();
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialUnusedTemplates.php b/includes/specials/SpecialUnusedTemplates.php
new file mode 100644 (file)
index 0000000..119ef87
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+/**
+ * Implements Special:Unusedtemplates
+ *
+ * Copyright © 2006 Rob Church
+ *
+ * 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 SpecialPage
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+/**
+ * A special page that lists unused templates
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialUnusedTemplates extends QueryPage {
+       function __construct( $name = 'Unusedtemplates' ) {
+               parent::__construct( $name );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       public function getQueryInfo() {
+               return [
+                       'tables' => [ 'page', 'templatelinks' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title'
+                       ],
+                       'conds' => [
+                               'page_namespace' => NS_TEMPLATE,
+                               'tl_from IS NULL',
+                               'page_is_redirect' => 0
+                       ],
+                       'join_conds' => [ 'templatelinks' => [
+                               'LEFT JOIN', [ 'tl_title = page_title',
+                                       'tl_namespace = page_namespace' ] ] ]
+               ];
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $linkRenderer = $this->getLinkRenderer();
+               $title = Title::makeTitle( NS_TEMPLATE, $result->title );
+               $pageLink = $linkRenderer->makeKnownLink(
+                       $title,
+                       null,
+                       [],
+                       [ 'redirect' => 'no' ]
+               );
+               $wlhLink = $linkRenderer->makeKnownLink(
+                       SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() ),
+                       $this->msg( 'unusedtemplateswlh' )->text()
+               );
+
+               return $this->getLanguage()->specialList( $pageLink, $wlhLink );
+       }
+
+       function getPageHeader() {
+               return $this->msg( 'unusedtemplatestext' )->parseAsBlock();
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialUnusedcategories.php b/includes/specials/SpecialUnusedcategories.php
deleted file mode 100644 (file)
index 2577a10..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-/**
- * Implements Special:Unusedcategories
- *
- * 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 SpecialPage
- */
-
-/**
- * @ingroup SpecialPage
- */
-class UnusedCategoriesPage extends QueryPage {
-       function __construct( $name = 'Unusedcategories' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function getPageHeader() {
-               return $this->msg( 'unusedcategoriestext' )->parseAsBlock();
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'page', 'categorylinks', 'page_props' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title'
-                       ],
-                       'conds' => [
-                               'cl_from IS NULL',
-                               'page_namespace' => NS_CATEGORY,
-                               'page_is_redirect' => 0,
-                               'pp_page IS NULL'
-                       ],
-                       'join_conds' => [
-                               'categorylinks' => [ 'LEFT JOIN', 'cl_to = page_title' ],
-                               'page_props' => [ 'LEFT JOIN', [
-                                       'page_id = pp_page',
-                                       'pp_propname' => 'expectunusedcategory'
-                               ] ]
-                       ]
-               ];
-       }
-
-       /**
-        * A should come before Z (T32907)
-        * @return bool
-        */
-       function sortDescending() {
-               return false;
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $title = Title::makeTitle( NS_CATEGORY, $result->title );
-
-               return $this->getLinkRenderer()->makeLink( $title, $title->getText() );
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-
-       public function preprocessResults( $db, $res ) {
-               $this->executeLBFromResultWrapper( $res );
-       }
-}
diff --git a/includes/specials/SpecialUnusedimages.php b/includes/specials/SpecialUnusedimages.php
deleted file mode 100644 (file)
index bcb3b85..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-/**
- * Implements Special:Unusedimages
- *
- * 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 SpecialPage
- */
-
-/**
- * A special page that lists unused images
- *
- * @ingroup SpecialPage
- */
-class UnusedimagesPage extends ImageQueryPage {
-       function __construct( $name = 'Unusedimages' ) {
-               parent::__construct( $name );
-       }
-
-       function isExpensive() {
-               return true;
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function getQueryInfo() {
-               $retval = [
-                       'tables' => [ 'image', 'imagelinks' ],
-                       'fields' => [
-                               'namespace' => NS_FILE,
-                               'title' => 'img_name',
-                               'value' => 'img_timestamp',
-                       ],
-                       'conds' => [ 'il_to IS NULL' ],
-                       'join_conds' => [ 'imagelinks' => [ 'LEFT JOIN', 'il_to = img_name' ] ]
-               ];
-
-               if ( $this->getConfig()->get( 'CountCategorizedImagesAsUsed' ) ) {
-                       // Order is significant
-                       $retval['tables'] = [ 'image', 'page', 'categorylinks',
-                               'imagelinks' ];
-                       $retval['conds']['page_namespace'] = NS_FILE;
-                       $retval['conds'][] = 'cl_from IS NULL';
-                       $retval['conds'][] = 'img_name = page_title';
-                       $retval['join_conds']['categorylinks'] = [
-                               'LEFT JOIN', 'cl_from = page_id' ];
-                       $retval['join_conds']['imagelinks'] = [
-                               'LEFT JOIN', 'il_to = page_title' ];
-               }
-
-               return $retval;
-       }
-
-       function usesTimestamps() {
-               return true;
-       }
-
-       function getPageHeader() {
-               if ( $this->getConfig()->get( 'CountCategorizedImagesAsUsed' ) ) {
-                       return $this->msg(
-                               'unusedimagestext-categorizedimgisused'
-                       )->parseAsBlock();
-               }
-               return $this->msg( 'unusedimagestext' )->parseAsBlock();
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialUnusedtemplates.php b/includes/specials/SpecialUnusedtemplates.php
deleted file mode 100644 (file)
index f73be43..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-/**
- * Implements Special:Unusedtemplates
- *
- * Copyright © 2006 Rob Church
- *
- * 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 SpecialPage
- * @author Rob Church <robchur@gmail.com>
- */
-
-/**
- * A special page that lists unused templates
- *
- * @ingroup SpecialPage
- */
-class UnusedtemplatesPage extends QueryPage {
-       function __construct( $name = 'Unusedtemplates' ) {
-               parent::__construct( $name );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       public function getQueryInfo() {
-               return [
-                       'tables' => [ 'page', 'templatelinks' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title'
-                       ],
-                       'conds' => [
-                               'page_namespace' => NS_TEMPLATE,
-                               'tl_from IS NULL',
-                               'page_is_redirect' => 0
-                       ],
-                       'join_conds' => [ 'templatelinks' => [
-                               'LEFT JOIN', [ 'tl_title = page_title',
-                                       'tl_namespace = page_namespace' ] ] ]
-               ];
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $linkRenderer = $this->getLinkRenderer();
-               $title = Title::makeTitle( NS_TEMPLATE, $result->title );
-               $pageLink = $linkRenderer->makeKnownLink(
-                       $title,
-                       null,
-                       [],
-                       [ 'redirect' => 'no' ]
-               );
-               $wlhLink = $linkRenderer->makeKnownLink(
-                       SpecialPage::getTitleFor( 'Whatlinkshere', $title->getPrefixedText() ),
-                       $this->msg( 'unusedtemplateswlh' )->text()
-               );
-
-               return $this->getLanguage()->specialList( $pageLink, $wlhLink );
-       }
-
-       function getPageHeader() {
-               return $this->msg( 'unusedtemplatestext' )->parseAsBlock();
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialUnwatchedPages.php b/includes/specials/SpecialUnwatchedPages.php
new file mode 100644 (file)
index 0000000..42adaa0
--- /dev/null
@@ -0,0 +1,139 @@
+<?php
+/**
+ * Implements Special:Unwatchedpages
+ *
+ * Copyright © 2005 Ævar Arnfjörð Bjarmason
+ *
+ * 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 SpecialPage
+ * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\IResultWrapper;
+use Wikimedia\Rdbms\IDatabase;
+
+/**
+ * A special page that displays a list of pages that are not on anyones watchlist.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialUnwatchedPages extends QueryPage {
+
+       function __construct( $name = 'Unwatchedpages' ) {
+               parent::__construct( $name, 'unwatchedpages' );
+       }
+
+       public function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       /**
+        * Pre-cache page existence to speed up link generation
+        *
+        * @param IDatabase $db
+        * @param IResultWrapper $res
+        */
+       public function preprocessResults( $db, $res ) {
+               if ( !$res->numRows() ) {
+                       return;
+               }
+
+               $batch = new LinkBatch();
+               foreach ( $res as $row ) {
+                       $batch->add( $row->namespace, $row->title );
+               }
+               $batch->execute();
+
+               $res->seek( 0 );
+       }
+
+       public function getQueryInfo() {
+               $dbr = wfGetDB( DB_REPLICA );
+               return [
+                       'tables' => [ 'page', 'watchlist' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_namespace'
+                       ],
+                       'conds' => [
+                               'wl_title IS NULL',
+                               'page_is_redirect' => 0,
+                               'page_namespace != ' . $dbr->addQuotes( NS_MEDIAWIKI ),
+                       ],
+                       'join_conds' => [ 'watchlist' => [
+                               'LEFT JOIN', [ 'wl_title = page_title',
+                                       'wl_namespace = page_namespace' ] ] ]
+               ];
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       function getOrderFields() {
+               return [ 'page_namespace', 'page_title' ];
+       }
+
+       /**
+        * Add the JS
+        * @param string|null $par
+        */
+       public function execute( $par ) {
+               parent::execute( $par );
+               $this->getOutput()->addModules( 'mediawiki.special.unwatchedPages' );
+               $this->addHelpLink( 'Help:Watchlist' );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $nt = Title::makeTitleSafe( $result->namespace, $result->title );
+               if ( !$nt ) {
+                       return Html::element( 'span', [ 'class' => 'mw-invalidtitle' ],
+                               Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) );
+               }
+
+               $text = MediaWikiServices::getInstance()->getContentLanguage()->
+                       convert( htmlspecialchars( $nt->getPrefixedText() ) );
+
+               $linkRenderer = $this->getLinkRenderer();
+
+               $plink = $linkRenderer->makeKnownLink( $nt, new HtmlArmor( $text ) );
+               $wlink = $linkRenderer->makeKnownLink(
+                       $nt,
+                       $this->msg( 'watch' )->text(),
+                       [ 'class' => 'mw-watch-link' ],
+                       [ 'action' => 'watch' ]
+               );
+
+               return $this->getLanguage()->specialList( $plink, $wlink );
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialUnwatchedpages.php b/includes/specials/SpecialUnwatchedpages.php
deleted file mode 100644 (file)
index 3c5de64..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-<?php
-/**
- * Implements Special:Unwatchedpages
- *
- * Copyright © 2005 Ævar Arnfjörð Bjarmason
- *
- * 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 SpecialPage
- * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- */
-
-use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\IResultWrapper;
-use Wikimedia\Rdbms\IDatabase;
-
-/**
- * A special page that displays a list of pages that are not on anyones watchlist.
- *
- * @ingroup SpecialPage
- */
-class UnwatchedpagesPage extends QueryPage {
-
-       function __construct( $name = 'Unwatchedpages' ) {
-               parent::__construct( $name, 'unwatchedpages' );
-       }
-
-       public function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       /**
-        * Pre-cache page existence to speed up link generation
-        *
-        * @param IDatabase $db
-        * @param IResultWrapper $res
-        */
-       public function preprocessResults( $db, $res ) {
-               if ( !$res->numRows() ) {
-                       return;
-               }
-
-               $batch = new LinkBatch();
-               foreach ( $res as $row ) {
-                       $batch->add( $row->namespace, $row->title );
-               }
-               $batch->execute();
-
-               $res->seek( 0 );
-       }
-
-       public function getQueryInfo() {
-               $dbr = wfGetDB( DB_REPLICA );
-               return [
-                       'tables' => [ 'page', 'watchlist' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_namespace'
-                       ],
-                       'conds' => [
-                               'wl_title IS NULL',
-                               'page_is_redirect' => 0,
-                               'page_namespace != ' . $dbr->addQuotes( NS_MEDIAWIKI ),
-                       ],
-                       'join_conds' => [ 'watchlist' => [
-                               'LEFT JOIN', [ 'wl_title = page_title',
-                                       'wl_namespace = page_namespace' ] ] ]
-               ];
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       function getOrderFields() {
-               return [ 'page_namespace', 'page_title' ];
-       }
-
-       /**
-        * Add the JS
-        * @param string|null $par
-        */
-       public function execute( $par ) {
-               parent::execute( $par );
-               $this->getOutput()->addModules( 'mediawiki.special.unwatchedPages' );
-               $this->addHelpLink( 'Help:Watchlist' );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $nt = Title::makeTitleSafe( $result->namespace, $result->title );
-               if ( !$nt ) {
-                       return Html::element( 'span', [ 'class' => 'mw-invalidtitle' ],
-                               Linker::getInvalidTitleDescription( $this->getContext(), $result->namespace, $result->title ) );
-               }
-
-               $text = MediaWikiServices::getInstance()->getContentLanguage()->
-                       convert( htmlspecialchars( $nt->getPrefixedText() ) );
-
-               $linkRenderer = $this->getLinkRenderer();
-
-               $plink = $linkRenderer->makeKnownLink( $nt, new HtmlArmor( $text ) );
-               $wlink = $linkRenderer->makeKnownLink(
-                       $nt,
-                       $this->msg( 'watch' )->text(),
-                       [ 'class' => 'mw-watch-link' ],
-                       [ 'action' => 'watch' ]
-               );
-
-               return $this->getLanguage()->specialList( $plink, $wlink );
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialWantedCategories.php b/includes/specials/SpecialWantedCategories.php
new file mode 100644 (file)
index 0000000..659650c
--- /dev/null
@@ -0,0 +1,130 @@
+<?php
+/**
+ * Implements Special:Wantedcategories
+ *
+ * Copyright © 2005 Ævar Arnfjörð Bjarmason
+ *
+ * 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 SpecialPage
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * A querypage to list the most wanted categories - implements Special:Wantedcategories
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialWantedCategories extends WantedQueryPage {
+       private $currentCategoryCounts;
+
+       function __construct( $name = 'Wantedcategories' ) {
+               parent::__construct( $name );
+       }
+
+       function getQueryInfo() {
+               return [
+                       'tables' => [ 'categorylinks', 'page' ],
+                       'fields' => [
+                               'namespace' => NS_CATEGORY,
+                               'title' => 'cl_to',
+                               'value' => 'COUNT(*)'
+                       ],
+                       'conds' => [ 'page_title IS NULL' ],
+                       'options' => [ 'GROUP BY' => 'cl_to' ],
+                       'join_conds' => [ 'page' => [ 'LEFT JOIN',
+                               [ 'page_title = cl_to',
+                                       'page_namespace' => NS_CATEGORY ] ] ]
+               ];
+       }
+
+       function preprocessResults( $db, $res ) {
+               parent::preprocessResults( $db, $res );
+
+               $this->currentCategoryCounts = [];
+
+               if ( !$res->numRows() || !$this->isCached() ) {
+                       return;
+               }
+
+               // Fetch (hopefully) up-to-date numbers of pages in each category.
+               // This should be fast enough as we limit the list to a reasonable length.
+
+               $allCategories = [];
+               foreach ( $res as $row ) {
+                       $allCategories[] = $row->title;
+               }
+
+               $categoryRes = $db->select(
+                       'category',
+                       [ 'cat_title', 'cat_pages' ],
+                       [ 'cat_title' => $allCategories ],
+                       __METHOD__
+               );
+               foreach ( $categoryRes as $row ) {
+                       $this->currentCategoryCounts[$row->cat_title] = intval( $row->cat_pages );
+               }
+
+               // Back to start for display
+               $res->seek( 0 );
+       }
+
+       /**
+        * @param Skin $skin
+        * @param object $result Result row
+        * @return string
+        */
+       function formatResult( $skin, $result ) {
+               $nt = Title::makeTitle( $result->namespace, $result->title );
+               $text = new HtmlArmor( MediaWikiServices::getInstance()->getContentLanguage()
+                       ->convert( htmlspecialchars( $nt->getText() ) ) );
+
+               if ( !$this->isCached() ) {
+                       // We can assume the freshest data
+                       $plink = $this->getLinkRenderer()->makeBrokenLink(
+                               $nt,
+                               $text
+                       );
+                       $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped();
+               } else {
+                       $plink = $this->getLinkRenderer()->makeLink( $nt, $text );
+
+                       $currentValue = $this->currentCategoryCounts[$result->title] ?? 0;
+                       $cachedValue = intval( $result->value ); // T76910
+
+                       // If the category has been created or emptied since the list was refreshed, strike it
+                       if ( $nt->isKnown() || $currentValue === 0 ) {
+                               $plink = "<del>$plink</del>";
+                       }
+
+                       // Show the current number of category entries if it changed
+                       if ( $currentValue !== $cachedValue ) {
+                               $nlinks = $this->msg( 'nmemberschanged' )
+                                       ->numParams( $cachedValue, $currentValue )->escaped();
+                       } else {
+                               $nlinks = $this->msg( 'nmembers' )->numParams( $cachedValue )->escaped();
+                       }
+               }
+
+               return $this->getLanguage()->specialList( $plink, $nlinks );
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialWantedTemplates.php b/includes/specials/SpecialWantedTemplates.php
new file mode 100644 (file)
index 0000000..453f7b8
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Implements Special:Wantedtemplates
+ *
+ * Copyright © 2008, Danny B.
+ * Based on SpecialWantedcategories.php by Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+ * makeWlhLink() taken from SpecialMostlinkedtemplates by Rob Church <robchur@gmail.com>
+ *
+ * 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 SpecialPage
+ * @author Danny B.
+ */
+
+/**
+ * A querypage to list the most wanted templates
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialWantedTemplates extends WantedQueryPage {
+       function __construct( $name = 'Wantedtemplates' ) {
+               parent::__construct( $name );
+       }
+
+       function getQueryInfo() {
+               return [
+                       'tables' => [ 'templatelinks', 'page' ],
+                       'fields' => [
+                               'namespace' => 'tl_namespace',
+                               'title' => 'tl_title',
+                               'value' => 'COUNT(*)'
+                       ],
+                       'conds' => [
+                               'page_title IS NULL',
+                               'tl_namespace' => NS_TEMPLATE
+                       ],
+                       'options' => [ 'GROUP BY' => [ 'tl_namespace', 'tl_title' ] ],
+                       'join_conds' => [ 'page' => [ 'LEFT JOIN',
+                               [ 'page_namespace = tl_namespace',
+                                       'page_title = tl_title' ] ] ]
+               ];
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialWantedcategories.php b/includes/specials/SpecialWantedcategories.php
deleted file mode 100644 (file)
index 5c62298..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-<?php
-/**
- * Implements Special:Wantedcategories
- *
- * Copyright © 2005 Ævar Arnfjörð Bjarmason
- *
- * 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 SpecialPage
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * A querypage to list the most wanted categories - implements Special:Wantedcategories
- *
- * @ingroup SpecialPage
- */
-class WantedCategoriesPage extends WantedQueryPage {
-       private $currentCategoryCounts;
-
-       function __construct( $name = 'Wantedcategories' ) {
-               parent::__construct( $name );
-       }
-
-       function getQueryInfo() {
-               return [
-                       'tables' => [ 'categorylinks', 'page' ],
-                       'fields' => [
-                               'namespace' => NS_CATEGORY,
-                               'title' => 'cl_to',
-                               'value' => 'COUNT(*)'
-                       ],
-                       'conds' => [ 'page_title IS NULL' ],
-                       'options' => [ 'GROUP BY' => 'cl_to' ],
-                       'join_conds' => [ 'page' => [ 'LEFT JOIN',
-                               [ 'page_title = cl_to',
-                                       'page_namespace' => NS_CATEGORY ] ] ]
-               ];
-       }
-
-       function preprocessResults( $db, $res ) {
-               parent::preprocessResults( $db, $res );
-
-               $this->currentCategoryCounts = [];
-
-               if ( !$res->numRows() || !$this->isCached() ) {
-                       return;
-               }
-
-               // Fetch (hopefully) up-to-date numbers of pages in each category.
-               // This should be fast enough as we limit the list to a reasonable length.
-
-               $allCategories = [];
-               foreach ( $res as $row ) {
-                       $allCategories[] = $row->title;
-               }
-
-               $categoryRes = $db->select(
-                       'category',
-                       [ 'cat_title', 'cat_pages' ],
-                       [ 'cat_title' => $allCategories ],
-                       __METHOD__
-               );
-               foreach ( $categoryRes as $row ) {
-                       $this->currentCategoryCounts[$row->cat_title] = intval( $row->cat_pages );
-               }
-
-               // Back to start for display
-               $res->seek( 0 );
-       }
-
-       /**
-        * @param Skin $skin
-        * @param object $result Result row
-        * @return string
-        */
-       function formatResult( $skin, $result ) {
-               $nt = Title::makeTitle( $result->namespace, $result->title );
-               $text = new HtmlArmor( MediaWikiServices::getInstance()->getContentLanguage()
-                       ->convert( htmlspecialchars( $nt->getText() ) ) );
-
-               if ( !$this->isCached() ) {
-                       // We can assume the freshest data
-                       $plink = $this->getLinkRenderer()->makeBrokenLink(
-                               $nt,
-                               $text
-                       );
-                       $nlinks = $this->msg( 'nmembers' )->numParams( $result->value )->escaped();
-               } else {
-                       $plink = $this->getLinkRenderer()->makeLink( $nt, $text );
-
-                       $currentValue = $this->currentCategoryCounts[$result->title] ?? 0;
-                       $cachedValue = intval( $result->value ); // T76910
-
-                       // If the category has been created or emptied since the list was refreshed, strike it
-                       if ( $nt->isKnown() || $currentValue === 0 ) {
-                               $plink = "<del>$plink</del>";
-                       }
-
-                       // Show the current number of category entries if it changed
-                       if ( $currentValue !== $cachedValue ) {
-                               $nlinks = $this->msg( 'nmemberschanged' )
-                                       ->numParams( $cachedValue, $currentValue )->escaped();
-                       } else {
-                               $nlinks = $this->msg( 'nmembers' )->numParams( $cachedValue )->escaped();
-                       }
-               }
-
-               return $this->getLanguage()->specialList( $plink, $nlinks );
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialWantedtemplates.php b/includes/specials/SpecialWantedtemplates.php
deleted file mode 100644 (file)
index 66e6814..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-/**
- * Implements Special:Wantedtemplates
- *
- * Copyright © 2008, Danny B.
- * Based on SpecialWantedcategories.php by Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- * makeWlhLink() taken from SpecialMostlinkedtemplates by Rob Church <robchur@gmail.com>
- *
- * 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 SpecialPage
- * @author Danny B.
- */
-
-/**
- * A querypage to list the most wanted templates
- *
- * @ingroup SpecialPage
- */
-class WantedTemplatesPage extends WantedQueryPage {
-       function __construct( $name = 'Wantedtemplates' ) {
-               parent::__construct( $name );
-       }
-
-       function getQueryInfo() {
-               return [
-                       'tables' => [ 'templatelinks', 'page' ],
-                       'fields' => [
-                               'namespace' => 'tl_namespace',
-                               'title' => 'tl_title',
-                               'value' => 'COUNT(*)'
-                       ],
-                       'conds' => [
-                               'page_title IS NULL',
-                               'tl_namespace' => NS_TEMPLATE
-                       ],
-                       'options' => [ 'GROUP BY' => [ 'tl_namespace', 'tl_title' ] ],
-                       'join_conds' => [ 'page' => [ 'LEFT JOIN',
-                               [ 'page_namespace = tl_namespace',
-                                       'page_title = tl_title' ] ] ]
-               ];
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
diff --git a/includes/specials/SpecialWithoutInterwiki.php b/includes/specials/SpecialWithoutInterwiki.php
new file mode 100644 (file)
index 0000000..36aea75
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+/**
+ * Implements Special:Withoutinterwiki
+ *
+ * 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 SpecialPage
+ * @author Rob Church <robchur@gmail.com>
+ */
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * Special page lists pages without language links
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialWithoutInterwiki extends PageQueryPage {
+       private $prefix = '';
+
+       function __construct( $name = 'Withoutinterwiki' ) {
+               parent::__construct( $name );
+       }
+
+       function execute( $par ) {
+               $this->prefix = Title::capitalize(
+                       $this->getRequest()->getVal( 'prefix', $par ), NS_MAIN );
+               parent::execute( $par );
+       }
+
+       function getPageHeader() {
+               # Do not show useless input form if special page is cached
+               if ( $this->isCached() ) {
+                       return '';
+               }
+
+               $formDescriptor = [
+                       'prefix' => [
+                               'label-message' => 'allpagesprefix',
+                               'name' => 'prefix',
+                               'id' => 'wiprefix',
+                               'type' => 'text',
+                               'size' => 20,
+                               'default' => $this->prefix
+                       ]
+               ];
+
+               $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() );
+               $htmlForm->setWrapperLegend( '' )
+                       ->setSubmitTextMsg( 'withoutinterwiki-submit' )
+                       ->setMethod( 'get' )
+                       ->prepareForm()
+                       ->displayForm( false );
+       }
+
+       function sortDescending() {
+               return false;
+       }
+
+       function getOrderFields() {
+               return [ 'page_namespace', 'page_title' ];
+       }
+
+       function isExpensive() {
+               return true;
+       }
+
+       function isSyndicated() {
+               return false;
+       }
+
+       function getQueryInfo() {
+               $query = [
+                       'tables' => [ 'page', 'langlinks' ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title'
+                       ],
+                       'conds' => [
+                               'll_title IS NULL',
+                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
+                                       getContentNamespaces(),
+                               'page_is_redirect' => 0
+                       ],
+                       'join_conds' => [ 'langlinks' => [ 'LEFT JOIN', 'll_from = page_id' ] ]
+               ];
+               if ( $this->prefix ) {
+                       $dbr = wfGetDB( DB_REPLICA );
+                       $query['conds'][] = 'page_title ' . $dbr->buildLike( $this->prefix, $dbr->anyString() );
+               }
+
+               return $query;
+       }
+
+       protected function getGroupName() {
+               return 'maintenance';
+       }
+}
diff --git a/includes/specials/SpecialWithoutinterwiki.php b/includes/specials/SpecialWithoutinterwiki.php
deleted file mode 100644 (file)
index 548e921..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-<?php
-/**
- * Implements Special:Withoutinterwiki
- *
- * 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 SpecialPage
- * @author Rob Church <robchur@gmail.com>
- */
-
-use MediaWiki\MediaWikiServices;
-
-/**
- * Special page lists pages without language links
- *
- * @ingroup SpecialPage
- */
-class WithoutInterwikiPage extends PageQueryPage {
-       private $prefix = '';
-
-       function __construct( $name = 'Withoutinterwiki' ) {
-               parent::__construct( $name );
-       }
-
-       function execute( $par ) {
-               $this->prefix = Title::capitalize(
-                       $this->getRequest()->getVal( 'prefix', $par ), NS_MAIN );
-               parent::execute( $par );
-       }
-
-       function getPageHeader() {
-               # Do not show useless input form if special page is cached
-               if ( $this->isCached() ) {
-                       return '';
-               }
-
-               $formDescriptor = [
-                       'prefix' => [
-                               'label-message' => 'allpagesprefix',
-                               'name' => 'prefix',
-                               'id' => 'wiprefix',
-                               'type' => 'text',
-                               'size' => 20,
-                               'default' => $this->prefix
-                       ]
-               ];
-
-               $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() );
-               $htmlForm->setWrapperLegend( '' )
-                       ->setSubmitTextMsg( 'withoutinterwiki-submit' )
-                       ->setMethod( 'get' )
-                       ->prepareForm()
-                       ->displayForm( false );
-       }
-
-       function sortDescending() {
-               return false;
-       }
-
-       function getOrderFields() {
-               return [ 'page_namespace', 'page_title' ];
-       }
-
-       function isExpensive() {
-               return true;
-       }
-
-       function isSyndicated() {
-               return false;
-       }
-
-       function getQueryInfo() {
-               $query = [
-                       'tables' => [ 'page', 'langlinks' ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title'
-                       ],
-                       'conds' => [
-                               'll_title IS NULL',
-                               'page_namespace' => MediaWikiServices::getInstance()->getNamespaceInfo()->
-                                       getContentNamespaces(),
-                               'page_is_redirect' => 0
-                       ],
-                       'join_conds' => [ 'langlinks' => [ 'LEFT JOIN', 'll_from = page_id' ] ]
-               ];
-               if ( $this->prefix ) {
-                       $dbr = wfGetDB( DB_REPLICA );
-                       $query['conds'][] = 'page_title ' . $dbr->buildLike( $this->prefix, $dbr->anyString() );
-               }
-
-               return $query;
-       }
-
-       protected function getGroupName() {
-               return 'maintenance';
-       }
-}
index 0f5355d..0abe842 100644 (file)
@@ -43,6 +43,12 @@ class ActiveUsersPager extends UsersPager {
         */
        private $blockStatusByUid;
 
+       /** @var int */
+       private $RCMaxAge;
+
+       /** @var string[] */
+       private $excludegroups;
+
        /**
         * @param IContextSource|null $context
         * @param FormOptions $opts
index c804b09..6b8b93b 100644 (file)
@@ -46,6 +46,11 @@ class AllMessagesTablePager extends TablePager {
         */
        protected $prefix;
 
+       /**
+        * @var string
+        */
+       protected $suffix;
+
        /**
         * @var Language
         */
index 9415cea..81c3ffb 100644 (file)
@@ -30,10 +30,15 @@ class MergeHistoryPager extends ReverseChronologicalPager {
        /** @var array */
        public $mConds;
 
+       /** @var int */
+       private $articleID;
+
+       /** @var int */
+       private $maxTimestamp;
+
        public function __construct( SpecialMergeHistory $form, $conds, Title $source, Title $dest ) {
                $this->mForm = $form;
                $this->mConds = $conds;
-               $this->title = $source;
                $this->articleID = $source->getArticleID();
 
                $dbr = wfGetDB( DB_REPLICA );
index 296fe11..a00b371 100644 (file)
@@ -34,6 +34,12 @@ class ProtectedTitlesPager extends AlphabeticPager {
         */
        public $mConds;
 
+       /** @var string|null */
+       private $level;
+
+       /** @var int|null */
+       private $namespace;
+
        /**
         * @param SpecialProtectedtitles $form
         * @param array $conds
@@ -50,7 +56,6 @@ class ProtectedTitlesPager extends AlphabeticPager {
                $this->mConds = $conds;
                $this->level = $level;
                $this->namespace = $namespace;
-               $this->size = intval( $size );
                parent::__construct( $form->getContext() );
        }
 
@@ -90,7 +95,7 @@ class ProtectedTitlesPager extends AlphabeticPager {
                        $conds['pt_create_perm'] = $this->level;
                }
 
-               if ( !is_null( $this->namespace ) ) {
+               if ( $this->namespace !== null ) {
                        $conds[] = 'pt_namespace=' . $this->mDb->addQuotes( $this->namespace );
                }
 
index 57b575b..ba078e9 100644 (file)
@@ -37,6 +37,24 @@ class UsersPager extends AlphabeticPager {
         */
        protected $userGroupCache;
 
+       /** @var string */
+       protected $requestedGroup;
+
+       /** @var bool */
+       protected $editsOnly;
+
+       /** @var bool */
+       protected $temporaryGroupsOnly;
+
+       /** @var bool */
+       protected $creationSort;
+
+       /** @var bool|null */
+       protected $including;
+
+       /** @var string */
+       protected $requestedUser;
+
        /**
         * @param IContextSource|null $context
         * @param array|null $par (Default null)
index 6893bf4..4445e1d 100644 (file)
@@ -1741,7 +1741,7 @@ class User implements IDBAccessObject, UserIdentity {
                // Avoid PHP 7.1 warning of passing $this by reference
                $thisUser = $this;
                // Extensions
-               Hooks::run( 'GetBlockedStatus', [ &$thisUser ] );
+               Hooks::run( 'GetBlockedStatus', [ &$thisUser ], '1.34' );
        }
 
        /**
@@ -3717,7 +3717,7 @@ class User implements IDBAccessObject, UserIdentity {
 
                                // If there is a new, unseen, revision, use its timestamp
                                $nextid = $oldid
-                                       ? $title->getNextRevisionID( $oldid, Title::GAID_FOR_UPDATE )
+                                       ? $title->getNextRevisionID( $oldid, Title::READ_LATEST )
                                        : null;
                                if ( $nextid ) {
                                        $this->setNewtalk( true, Revision::newFromId( $nextid ) );
index 06d8095..3ae00ea 100644 (file)
@@ -9,14 +9,22 @@ namespace MediaWiki\Widget;
  * @license MIT
  */
 class CheckMatrixWidget extends \OOUI\Widget {
-
-       protected $name = '';
-       protected $columns = [];
-       protected $rows = [];
-       protected $tooltips = [];
-       protected $values = [];
-       protected $forcedOn = [];
-       protected $forcedOff = [];
+       /** @var string|null */
+       protected $name;
+       /** @var string|null */
+       protected $id;
+       /** @var array */
+       protected $columns;
+       /** @var array */
+       protected $rows;
+       /** @var array */
+       protected $tooltips;
+       /** @var array */
+       protected $values;
+       /** @var array */
+       protected $forcedOn;
+       /** @var array */
+       protected $forcedOff;
 
        /**
         * Operates similarly to MultiSelectWidget, but instead of using an array of
index 7737067..913816c 100644 (file)
@@ -9,7 +9,8 @@ namespace MediaWiki\Widget;
  * @license MIT
  */
 class ComplexTitleInputWidget extends \OOUI\Widget {
-
+       /** @var array */
+       protected $config;
        protected $namespace = null;
        protected $title = null;
 
index 7802a2a..a360fb8 100644 (file)
@@ -9,8 +9,10 @@ namespace MediaWiki\Widget;
  * @license MIT
  */
 class NamespaceInputWidget extends \OOUI\DropdownInputWidget {
-
-       protected $includeAllValue = null;
+       /** @var string */
+       protected $includeAllValue;
+       /** @var int[] */
+       protected $exclude;
 
        /**
         * @param array $config Configuration options
index a946653..a792172 100644 (file)
@@ -12,9 +12,12 @@ use OOUI\TextInputWidget;
  * @license MIT
  */
 class SelectWithInputWidget extends \OOUI\Widget {
-
-       protected $textinput = null;
-       protected $dropdowninput = null;
+       /** @var array */
+       protected $config;
+       /** @var TextInputWidget */
+       protected $textinput;
+       /** @var DropdownInputWidget */
+       protected $dropdowninput;
 
        /**
         * A version of the SelectWithInputWidget, with `or` set to true.
index 18c05bf..26935b1 100644 (file)
@@ -13,9 +13,14 @@ use \OOUI\LabelWidget;
  * @license MIT
  */
 class SizeFilterWidget extends \OOUI\Widget {
-
-       protected $radioselectinput = null;
-       protected $textinput = null;
+       /** @var array */
+       protected $config;
+       /** @var LabelWidget */
+       protected $label;
+       /** @var RadioSelectInputWidget */
+       protected $radioselectinput;
+       /** @var TextInputWidget */
+       protected $textinput;
 
        /**
         * RadioSelectInputWidget and a TextInputWidget to set minimum or maximum byte size
index 43e184c..e96160c 100644 (file)
@@ -12,41 +12,34 @@ use OOUI\MultilineTextInputWidget;
  * @license MIT
  */
 abstract class TagMultiselectWidget extends \OOUI\Widget {
-
-       protected $selectedArray = [];
-       protected $inputName = null;
-       protected $inputPlaceholder = null;
-       protected $tagLimit = null;
+       /** @var array */
+       protected $selectedArray;
+       /** @var string|null */
+       protected $inputName;
+       /** @var string|null */
+       protected $inputPlaceholder;
+       /** @var array */
+       protected $input;
+       /** @var int|null */
+       protected $tagLimit;
 
        /**
         * @param array $config Configuration options
         *   - array $config['default'] Array of items to use as preset data
-        *   - array $config['name'] Name attribute (used in forms)
-        *   - array $config['placeholder'] Placeholder message for input
+        *   - string $config['name'] Name attribute (used in forms)
+        *   - string $config['placeholder'] Placeholder message for input
         *   - array $config['input'] Config options for the input widget
-        *   - number $config['tagLimit'] Maximum number of selected items
+        *   - int $config['tagLimit'] Maximum number of selected items
         */
        public function __construct( array $config = [] ) {
                parent::__construct( $config );
 
                // Properties
-               if ( isset( $config['default'] ) ) {
-                       $this->selectedArray = $config['default'];
-               }
-               if ( isset( $config['name'] ) ) {
-                       $this->inputName = $config['name'];
-               }
-               if ( isset( $config['placeholder'] ) ) {
-                       $this->inputPlaceholder = $config['placeholder'];
-               }
-               if ( isset( $config['input'] ) ) {
-                       $this->input = $config['input'];
-               } else {
-                       $this->input = [];
-               }
-               if ( isset( $config['tagLimit'] ) ) {
-                       $this->tagLimit = $config['tagLimit'];
-               }
+               $this->selectedArray = $config['default'] ?? [];
+               $this->inputName = $config['name'] ?? null;
+               $this->inputPlaceholder = $config['placeholder'] ?? null;
+               $this->input = $config['input'] ?? [];
+               $this->tagLimit = $config['tagLimit'] ?? null;
 
                $textarea = new MultilineTextInputWidget( array_merge( [
                        'name' => $this->inputName,
index 15f5ee1..e8c22b4 100644 (file)
        "content-model-css": "CSS",
        "content-json-empty-object": "Prázdný objekt",
        "content-json-empty-array": "Prázdné pole",
+       "unsupported-content-model": "<strong>Varování:</strong> Model obsahu $1 není na této wiki podporován.",
+       "unsupported-content-diff": "Rozdíly obsahů s modelem $1 nejsou podporovány.",
+       "unsupported-content-diff2": "Rozdíly mezi obsahy s modely $1 a $2 nejsou na této wiki podporovány.",
        "deprecated-self-close-category": "Stránky s neplatnými sebeuzavírajícími HTML značkami",
        "deprecated-self-close-category-desc": "Stránka obsahuje neplatné sebeuzavírající HTML značky, například <code>&lt;b/></code> nebo <code>&lt;span/></code>. Jejich chování se v zájmu konzistence se specifikací HTML5 brzy změní, proto je jejich použití ve wikitextu zastaralé.",
        "duplicate-args-warning": "<strong>Upozornění:</strong> Stránka [[:$1]] volá [[:$2]] s více než jednou hodnotou parametru „$3“. Použije se jen poslední uvedená hodnota.",
        "undo-norev": "Tuto editaci není možné vrátit, protože neexistuje nebo byla smazána.",
        "undo-nochange": "Zdá se, že editace již byla zrušena.",
        "undo-summary": "Zrušena verze $1 od uživatele [[Special:Contributions/$2|$2]] ([[User talk:$2|diskuse]])",
+       "undo-summary-anon": "Zrušena verze $1 od uživatele [[Special:Contributions/$2|$2]]",
        "undo-summary-username-hidden": "Zrušena verze $1 od skrytého uživatele",
        "cantcreateaccount-text": "Zakládání nových účtů z této IP adresy (<strong>$1</strong>) bylo zablokováno {{GENDER:$3|uživatelem|uživatelkou}} [[User:$3|$3]].\n\n$3 uvádí toto zdůvodnění: <em>$2</em>",
        "cantcreateaccount-range-text": "Zakládání nových účtů z IP adres v rozsahu <strong>$1</strong>, který obsahuje i vaši IP adresu (<strong>$4</strong>), bylo zablokováno {{GENDER:$3|uživatelem|uživatelkou}} [[User:$3|$3]].\n\n$3 uvádí toto zdůvodnění: <em>$2</em>",
        "alreadyrolled": "Nelze vrátit zpět poslední editaci [[:$1]] od uživatele [[User:$2|$2]] ([[User talk:$2|diskuse]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]), protože někdo jiný již stránku editoval nebo vrátil tuto změnu zpět.\n\nPoslední editaci této stránky {{GENDER:$3|provedl|provedla|provedl uživatel}} [[User:$3|$3]] ([[User talk:$3|diskuse]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Shrnutí editace bylo: <em>$1</em>.",
        "revertpage": "Editace uživatele „[[Special:Contributions/$2|$2]]“ ([[User talk:$2|diskuse]]) vráceny do předchozího stavu, jehož autorem je „[[User:$1|$1]]“",
+       "revertpage-anon": "Editace uživatele „[[Special:Contributions/$2|$2]]“ vráceny do předchozího stavu, jehož autorem je „[[User:$1|$1]]“",
        "revertpage-nouser": "Editace skrytého uživatele vráceny do předchozího stavu, jehož {{GENDER:$1|autorem|autorkou}} je „[[User:$1|$1]]“",
        "rollback-success": "Editace {{GENDER:$3|uživatele|uživatelky}} $1 byly vráceny na poslední verzi od {{GENDER:$4|uživatele|uživatelky}} $2.",
        "sessionfailure-title": "Chyba relace",
index 6ba40ff..b64046b 100644 (file)
        "checkbox-all": "Pêro",
        "checkbox-none": "Çıniyo",
        "checkbox-invert": "Dimlaşt ke",
-       "allpages": "Pêro peli",
+       "allpages": "Perri pêro",
        "nextpage": "Pela bahdoyêne ($1)",
        "prevpage": "Pela veri ($1)",
        "allpagesfrom": "Herfa kı pa liste bo:",
index f6ea46c..82826c5 100644 (file)
@@ -47,6 +47,7 @@
        "tog-useeditwarning": "Warn me when I leave an edit page with unsaved changes",
        "tog-prefershttps": "Always use a secure connection while logged in",
        "tog-showrollbackconfirmation": "Show a confirmation prompt when clicking on a rollback link",
+       "tog-requireemail": "Require email for password resets",
        "underline-always": "Always",
        "underline-never": "Never",
        "underline-default": "Skin or browser default",
        "prefs-help-email": "Email address is optional, but is needed for password resets, should you forget your password.",
        "prefs-help-email-others": "You can also choose to let others contact you by email through a link on your user or talk page.\nYour email address is not revealed when other users contact you.",
        "prefs-help-email-required": "Email address is required.",
+       "prefs-help-requireemail": "If checked, will only send password reset emails if the resetting person has provided both username and email for this account.",
        "prefs-info": "Basic information",
        "prefs-i18n": "Internationalisation",
        "prefs-signature": "Signature",
        "ipblocklist-legend": "Find a blocked user",
        "blocklist-userblocks": "Hide account blocks",
        "blocklist-tempblocks": "Hide temporary blocks",
+       "blocklist-indefblocks": "Hide indefinite blocks",
        "blocklist-addressblocks": "Hide single IP blocks",
        "blocklist-type": "Type:",
        "blocklist-type-opt-all": "All",
index f8709f3..64725b4 100644 (file)
@@ -6,7 +6,8 @@
                        "Matma Rex",
                        "Sp5uhe",
                        "Stlmch",
-                       "Railfail536"
+                       "Railfail536",
+                       "Rail"
                ]
        },
        "exif-imagewidth": "Szerokość",
index 5132718..41b2293 100644 (file)
        "blockedtitle": "L’utilisateur est bloqué.",
        "blocked-email-user": "<strong>Votre nom d’utilisateur a été bloqué pour l’envoi de courriels. Vous pouvez toujours modifier d’autres pages sur ce wiki.</strong> Vous pouvez voir tous les détails du blocage sur [[Special:MyContributions|contributions du compte]].\n\nCe blocage a été fait par $1.\n\nLe motif fourni est <em>$2</em>.\n\n* Début du blocage : $8\n* Expiration du blocage : $6\n* Cible souhaitée du blocage : $7\n* ID du blocage nº $5",
        "blockedtext-partial": "<strong>Votre nom d’utilisateur ou votre adresse IP a été bloqué pour effectuer des modifications sur cette page. Vous pouvez toujours modifier d’autres pages sur ce wiki.</strong> Vous pouvez voir tous les détails sur ce blocage sur [[Special:MyContributions|contributions du compte]].\n\nLe blocage a été effectué par $1.\n\nLe motif fourni est <em>$2</em>.\n\n* Début du blocage : $8\n* Expiration du blocage : $6\n* Cible souhaitée du blocage : $7\n* ID du blocage nº $5",
-       "blockedtext": "<strong>Votre compte utilisateur ou votre adresse IP a été bloqué.</strong>\n\nLe blocage a été effectué par $1.\nLa raison invoquée est la suivante : <em>$2</em>.\n\n* Début du blocage : $8\n* Expiration du blocage : $6\n* Compte bloqué : $7.\n\nVous pouvez contacter $1 ou un autre [[{{MediaWiki:Grouppage-sysop}}|administrateur]] pour en discuter.\nVous ne pouvez utiliser la fonction « {{int:emailuser}} » que si une adresse de courriel valide est spécifiée dans vos [[Special:Preferences|préférences]] et que si cette fonctionnalité ne vous a pas été bloquée.\nVotre adresse IP actuelle est $3 et votre identifiant de blocage est $5.\nVeuillez inclure tous les détails ci-dessus dans chacune des requêtes que vous ferez.",
-       "autoblockedtext": "Votre adresse IP a été bloquée automatiquement car elle a été utilisée par un autre utilisateur, lui-même bloqué par $1.\nLa raison invoquée est :\n\n: <em>$2</em>.\n\n* Début du blocage : $8\n* Expiration du blocage : $6\n* Compte bloqué : $7\n\nVous pouvez contacter $1 ou l’un des autres [[{{MediaWiki:Grouppage-sysop}}|administrateurs]] pour discuter de ce blocage.\n\nNotez que vous ne pourrez utiliser la fonctionnalité « {{int:emailuser}} » que si vous avez une adresse de courriel validée dans vos [[Special:Preferences|préférences]] et que cette fonctionnalité ne vous a pas été désactivée.\n\nVotre adresse IP actuelle est $3, et le numéro de blocage est $5.\nVeuillez inclure tous les détails ci-dessus dans chacune des requêtes que vous ferez.",
+       "blockedtext": "<strong>Votre compte utilisateur ou votre adresse IP a été bloqué.</strong>\n\nLe blocage a été effectué par $1.\nLa raison invoquée est la suivante: <em>$2</em>.\n\n* Début du blocage : $8\n* Expiration du blocage : $6\n* Compte bloqué : $7.\n\nVous pouvez contacter $1 ou un autre [[{{MediaWiki:Grouppage-sysop}}|administrateur]] pour en discuter.\nVous ne pouvez utiliser la fonction « {{int:emailuser}} » que si une adresse de courriel valide est spécifiée dans vos [[Special:Preferences|préférences]] et que si cette fonctionnalité ne vous a pas été bloquée.\nVotre adresse IP actuelle est $3 et votre identifiant de blocage est $5.\nVeuillez inclure tous les détails ci-dessus dans chacune des requêtes que vous ferez.",
+       "autoblockedtext": "Votre adresse IP a été bloquée automatiquement car elle a été utilisée par un autre utilisateur, lui-même bloqué par $1.\nLa raison invoquée est:\n\n: <em>$2</em>.\n\n* Début du blocage : $8\n* Expiration du blocage : $6\n* Compte bloqué : $7\n\nVous pouvez contacter $1 ou l’un des autres [[{{MediaWiki:Grouppage-sysop}}|administrateurs]] pour discuter de ce blocage.\n\nNotez que vous ne pourrez utiliser la fonctionnalité « {{int:emailuser}} » que si vous avez une adresse de courriel validée dans vos [[Special:Preferences|préférences]] et que cette fonctionnalité ne vous a pas été désactivée.\n\nVotre adresse IP actuelle est $3, et le numéro de blocage est $5.\nVeuillez inclure tous les détails ci-dessus dans chacune des requêtes que vous ferez.",
        "systemblockedtext": "Votre nom d'utilisateur ou votre adresse IP ont été bloqués automatiquement par MediaWiki.\nLa raison donnée est la suivante:\n\n: <em>$2</em>.\n\n* Le début du blocage: $8\n* Expiration du délai de blocage: $6\n* Elément concerné: $7\n\nVotre adresse IP actuelle est $3.\nVeuillez inclure tous les détails ci-dessus dans chacune des requêtes que vous ferez.",
        "blockednoreason": "aucune raison donnée",
        "blockedtext-composite": "<strong>Votre nom d'utilisateur ou votre adresse IP ont été bloqués.</strong>\n\nLa raison invoquée est :\n\n: <em>$2</em>.\n\n* Début du blocage : $8\n* Expiration du blocage le plus long : $6\n* $5\n\nVotre adresse IP actuelle est $3.\nVeuillez inclure tous les détails ci-dessus dans chaque demande que vous ferez.",
        "blocked-notice-logextract": "Cet utilisateur est actuellement bloqué.\nLa dernière entrée du journal des blocages est affichée ci-dessous pour référence :",
        "clearyourcache": "<strong>Note :</strong> après avoir enregistré vos modifications, il se peut que vous deviez forcer le rechargement complet du cache de votre navigateur pour voir les changements.\n* <strong>Firefox / Safari :</strong> maintenez la touche <em>Maj</em> (<em>Shift</em>) en cliquant sur le bouton <em>Actualiser</em> ou pressez <em>Ctrl-F5</em> ou <em>Ctrl-R</em> (<em>⌘-R</em> sur un Mac) \n* <strong>Google Chrome :</strong> appuyez sur <em>Ctrl-Maj-R</em> (<em>⌘-Shift-R</em> sur un Mac) \n* <strong>Internet Explorer :</strong> maintenez la touche <em>Ctrl</em> en cliquant sur le bouton <em>Actualiser</em> ou pressez <em>Ctrl-F5</em> \n* <strong>Opera :</strong> allez dans <em>Menu → Settings</em> (<em>Opera → Préférences</em> sur un Mac) et ensuite à <em>Confidentialité & sécurité → Effacer les données d’exploration → Images et fichiers en cache</em>.",
        "usercssyoucanpreview": "<strong>Astuce :</strong> utilisez le bouton « {{int:showpreview}} » pour tester votre nouvelle feuille CSS avant de l’enregistrer.",
-       "userjsonyoucanpreview": "<strong>Conseil :</strong> Utiliser le bouton « {{int:showpreview}} » pour tester votre nouveau JSON avant enregistrement.",
+       "userjsonyoucanpreview": "<strong>Conseil :</strong> utilisez le bouton « {{int:showpreview}} » pour tester votre nouveau JSON avant enregistrement.",
        "userjsyoucanpreview": "<strong>Astuce :</strong> utilisez le bouton « {{int:showpreview}} » pour tester votre nouvelle feuille JavaScript avant de l’enregistrer.",
        "usercsspreview": "<strong>Rappelez-vous que vous ne faites que prévisualiser votre propre feuille CSS. \nElle n’a pas encore été enregistrée !</strong>",
        "userjsonpreview": "<strong>Rappelez-vous que vous êtes seulement en train de tester/voir un aperçu de votre configuration utilisateur JSON.\nElle n’a pas encore été enregistrée !</strong>",
        "sitecsspreview": "<strong>Rappelez-vous que vous ne faites que prévisualiser cette feuille de style. \nElle n’a pas encore été enregistrée !</strong>",
        "sitejsonpreview": "<strong>Souvenez-vous que vous ne faites que regarder un aperçu de cette configuration JSON.\nElle n’a pas encore été enregistrée !</strong>",
        "sitejspreview": "<strong>Rappelez-vous que vous ne faites que prévisualiser ce code JavaScript. \nIl n’a pas encore été enregistré !</strong>",
-       "userinvalidconfigtitle": "<strong>Attention :</strong> il n’existe pas d’habillage « $1 ». \nLes pages personnelles avec extensions .css, .json et .js utilisent des titres en minuscules, par exemple {{ns:user}}:Foo/vector.css et non {{ns:user}}:Foo/Vector.css.",
+       "userinvalidconfigtitle": "<strong>Attention :</strong> il n’existe pas d’habillage « $1 ».\nLes pages personnelles avec extensions .css, .json et .js utilisent des titres en minuscules, par exemple {{ns:user}}:Foo/vector.css et non {{ns:user}}:Foo/Vector.css.",
        "updated": "(Mis à jour)",
        "note": "<strong>Note :</strong>",
        "previewnote": "<strong>Rappelez-vous que ce n’est qu’une prévisualisation.</strong>\nVos modifications n’ont pas encore été enregistrées !",
        "uploaded-event-handler-on-svg": "Fixer des attributs de gestionnaire d’événement <code>$1=\"$2\"</code> n’est pas autorisé dans les fichiers SVG.",
        "uploaded-href-attribute-svg": "<a> les éléments ne peuvent être liés (href) qu’aux cibles de données : (fichier inclus), http:// ou https://, ou un fragment (#, même document). Pour les autres éléments, comme <image>, seuls data: et fragment sont autorisés. Essayez les images incluses lors de l’export de votre SVG. <code>&lt;$1 $2=\"$3\"&gt;</code> obtenu.",
        "uploaded-href-unsafe-target-svg": "Un href vers des données non sûres a été trouvé dans le fichier SVG téléversé : URI cible <code>&lt;$1 $2=\"$3\"&gt;</code>.",
-       "uploaded-animate-svg": "Balise « animate » trouvée, qui pourrait modifier le href en utilisant l’attribut « from » <code>&lt;$1 $2=\"$3\"&gt;</code> dans le fichier SVG téléversé.",
+       "uploaded-animate-svg": "Balise « animate » trouvée qui pourrait modifier le href en utilisant l’attribut « from » <code>&lt;$1 $2=\"$3\"&gt;</code> dans le fichier SVG téléversé.",
        "uploaded-setting-event-handler-svg": "Positionner les attributs du gestionnaire d’événements n'est pas possible, <code>&lt;$1 $2=\"$3\"&gt;</code> trouvé dans le fichier SVG téléversé.",
        "uploaded-setting-href-svg": "L’utilisation de la balise « set » pour ajouter un attribut « href » à l’élément parent est interdite.",
-       "uploaded-wrong-setting-svg": "L’utilisation de la balise « set » pour ajouter une cible distante, de données ou de type script,  à un attribut quelconque, est interdite. <code>&lt;set to=\"$1\"&gt;</code> a été trouvé dans le fichier SVG téléversé.",
+       "uploaded-wrong-setting-svg": "L’utilisation de la balise « set » pour ajouter à un attribut quelconque une cible distante, de données ou de script est interdite. <code>&lt;set to=\"$1\"&gt;</code> a été trouvé dans le fichier SVG téléversé.",
        "uploaded-setting-handler-svg": "Les SVG qui positionnent l’attribut « handler » avec distant/données/script sont bloqués. <code>$1=\"$2\"</code> a été trouvé dans le fichier SVG téléversé.",
        "uploaded-remote-url-svg": "Les SVG qui positionnent un attribut de style avec une URL distante sont bloqués. <code>$1=\"$2\"</code> trouvé dans le fichier SVG téléversé.",
        "uploaded-image-filter-svg": "Filtre d’image avec URL trouvé : <code>&lt;$1 $2=\"$3\"&gt;</code> dans le fichier SVG téléversé.",
        "uploadstash-errclear": "La suppression des fichiers a échoué.",
        "uploadstash-refresh": "Actualiser la liste des fichiers",
        "uploadstash-thumbnail": "afficher la vignette",
-       "uploadstash-exception": "Impossible de stocker le téléversement dans la réserve ($1) : « $2 ».",
+       "uploadstash-exception": "Impossible de stocker le téléversement dans la réserve ($1): « $2 ».",
        "uploadstash-bad-path": "Le chemin n’existe pas.",
        "uploadstash-bad-path-invalid": "Le chemin n’est pas valide.",
        "uploadstash-bad-path-unknown-type": "Type « $1 » inconnu.",
index 9faad52..2a427a2 100644 (file)
        "category-file-count": "{{PLURAL:$2|ह्या वर्गांत फकत सकयली फायल आसपावता.|ह्या वर्गांत सकयल दिल्लीं {{PLURAL:$1|फायल|$1 फायलीं}} आसता, वट्ट फायलीं $2}}",
        "listingcontinuesabbrev": "चालू.",
        "noindex-category": "बिननिर्देशांकी पानां",
+       "broken-file-category": "तुटलेल्या फायलींचो दुवे आसलेलीं पानां",
        "about": "विशीं",
        "article": "मजकूराचीं पानां",
        "newwindow": "(नव्या ज़ोणेलांत उकतें जाता)",
        "mainpage-nstab": "मुखेल पान",
        "nosuchaction": "असले तरेचे कार्य ना",
        "nosuchspecialpage": "असले कांयच विशेश पान ना",
+       "nospecialpagetext": "<strong>तुवें एक अवैद खेरीत पान मागलां.</strong>\n\nएक खेरीत पानाची वळेरी तुका हांगासर मेळूं येता [[Special:SpecialPages|{{int:specialpages}}]].",
        "error": "चूक",
        "databaseerror": "डॅटाबॅज त्रुटी",
        "databaseerror-textcl": "डॅटाबेज विरोध त्रुटी आयिल्ली आसा",
        "badtitle": "चुकीचो माथाळो",
        "badtitletext": "विनवणी केल्लें पानाचो माथाळो अवैध, रितो वा अयोग्य तरेन आंतरभाशी वा आंतर विकी माथाळ्या कडे जोडिल्लो आशिल्लो. तातूंत माथाळ्यांत वापरुं नजो अशी एक वा चड अक्षरां आसूं येतात.",
        "viewsource": "उगम पळेयात",
+       "viewsource-title": "$1‎ खातीर मूळ पळय",
+       "viewsourcetext": "तुज्यान ह्या पानाचें मूळ पळोवंक आनी नकल करुंक जाता.",
        "yourname": "वापरप्याचे नांव",
        "userlogin-yourname": "वापरप्याचे नांव",
        "userlogin-yourname-ph": "वापरप्याचे नांव घालात",
        "accmailtitle": "गुपीत उतर धाडलां",
        "newarticle": "(नवें)",
        "newarticletext": "जें पान अजून अस्तित्वांत ना अशा पानाचे दुवे फाटल्यान तुमी आसात. पान रचपाक सकयले चौकटींत टायप करपाक सुरु करात (चड म्हायती खातीर [$1 आदाराचें पान] पळेयात) जर ह्या पानार तुमी चुकून पावल्यात तर ब्रावजराचो बॅक (<strong>फटीं</strong>) हो बटन दामात",
-       "noarticletext": "सदà¥\8dया à¤¹à¥\8dया à¤ªà¤¾à¤¨à¤¾à¤\9aà¥\87र à¤\95सलà¥\80à¤\9a à¤®à¤\9cà¤\95à¥\82र à¤¨à¤¾. \nतà¥\81मà¥\80 à¤¹à¥\87र à¤ªà¤¾à¤¨à¤¾à¤\82à¤\9aà¥\87र [[Special:Search/{{PAGENAME}}|हà¥\8b à¤®à¤¾à¤¥à¤¾à¤³à¥\8b]] à¤¸à¥\8bदà¥\82à¤\82 à¤¶à¤\95तात,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} à¤¸à¤\82बà¤\82दà¥\80त à¤²à¥\89à¤\97 à¤¸à¥\8bदà¥\82à¤\82 à¤¶à¤\95तात],\nवा à¤¹à¥\8dया à¤ªà¤¾à¤¨à¤¾à¤\95 [{{fullurl:{{FULLPAGENAME}}|action=edit}} à¤¸à¤\82पादà¥\80त] à¤\95रà¥\82à¤\82 à¤¶à¤\95तात</span>।",
+       "noarticletext": "सधà¥\8dयाà¤\95 à¤¹à¥\87à¤\82 à¤ªà¤¾à¤¨ à¤°à¤¿à¤\82तà¥\87 à¤\86सा.\nतà¥\81à¤\9cà¥\8dयान à¤¦à¥\82सऱà¥\8dया à¤ªà¤¾à¤¨à¤¾à¤¨à¥\80 [[Special:Search/{{PAGENAME}}| à¤¹à¥\8dया à¤ªà¤¾à¤¨à¤¾à¤\9aà¥\87 à¤¨à¤¾à¤\82व à¤¸à¥\8bदà¥\82à¤\82à¤\95 à¤\9cाता]], <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAME}}}} à¤¸à¤\82बà¤\82धà¥\80 à¤¸à¤¤à¥\8dरानà¥\80 à¤¸à¥\8bदà¥\82à¤\82à¤\95 à¤\9cाता], à¤µà¤¾ [{{fullurl:{{FULLPAGENAME}}|action=edit}} à¤¹à¥\87à¤\82 à¤ªà¤¾à¤¨ à¤°à¤\9aà¥\82à¤\82à¤\95 à¤\9cाता]</span>.",
        "noarticletext-nopermission": "तुर्ताक ह्या पानाचेर कसलोच मजकूर ना. तुमी हेर पानांचेर [[Special:Search/{{PAGENAME}}|ह्या माथाळ्याचो सोद]] घेवं शकतात,\nवा <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} संबंदीत लॉग सोदूं शकतात]</span>, पूण तुमकां हें पानाची रचणूक करपाची परवानगी ना।",
        "userpage-userdoesnotexist-view": "\"$1\" ह्या वापरप्याच्या खात्याची नोंदणी करूंक ना.",
        "previewnote": "'''ही फकत एक दाखवण हें मतींत दवरात.'''\nतुमचें बदल आडून राखून दवरूंक ना!",
        "hiddencategories": "हें पान {{PLURAL:$1|लिपिल्ले वर्गाचें}} आसा",
        "permissionserrorstext-withaction": "ह्या {{PLURAL:$1|कारण|कारणां}}: खातीर तुका $2 मान्यताय ना.",
        "recreate-moveddeleted-warn": "शिटकावणीः तुमी आदीं काडून उडयिल्लें पान परतून तयार करतात ह्या पानाचे फासून उडोवपी आनी दुसरे कडे व्हरपी लाग फकत सोपेपणा खातीर दिल्यात",
-       "moveddeleted-notice": "हà¥\87à¤\82 à¤ªà¤¾à¤¨ à¤\95ाडà¥\82न à¤\89डयला.\nहà¥\8dया à¤ªà¤¾à¤¨à¤¾à¤\9aà¥\8b à¤\95ाडà¥\82न à¤\89डà¥\8bवपà¥\80 à¤\86नà¥\80 à¤¹à¤¾à¤²à¥\8bवपà¥\80 à¤²à¥\89à¤\97 संदर्भा खातीर सकयल दिला.",
+       "moveddeleted-notice": "हà¥\87à¤\82 à¤ªà¤¾à¤¨ à¤\95ाडà¥\82न à¤\89डयला.\nहà¥\8dया à¤ªà¤¾à¤¨à¤¾à¤\9aà¥\87à¤\82 à¤\95ाडà¥\82न à¤\89डà¥\8bवपाà¤\9aà¥\87à¤\82, à¤°à¤¾à¤\96पाà¤\9aà¥\87à¤\82, à¤\86नà¥\80 à¤¹à¤¾à¤²à¥\8bवपाà¤\9aà¥\87à¤\82 à¤¸à¤¤à¥\8dर  संदर्भा खातीर सकयल दिला.",
        "content-model-wikitext": "विकीमजकूर",
        "content-model-text": "सादोमजकूर",
        "post-expand-template-inclusion-warning": "<strong>शिटकावणीः</strong> सांचो धरून आकार अगडबंब जाता, कांय सांच्याचो आसपाव जावचो ना.",
        "page_first": "पयलें",
        "page_last": "निमणें",
        "histlegend": "फरकाची निवडणी : पुनर्नियाळांची तुळा करपा खातीर रेडियो चौकटीं चेर कुरु करात आनी ''एंटर'' ना तर तळाकडे आशिल्लो बुतांव दामात।<br />\nविवरण : <strong>({{int:cur}})</strong> = हालींची पुनर्नियाळा बरोबर फरक, <strong>({{int:last}})</strong> = आदली पुनर्नियाळा बरोबर फरक, <strong>{{int:minoreditletter}}</strong> = दाक्टें बदल।",
-       "history-fieldset-title": "à¤\9aाळपाà¤\9aà¥\8b à¤\87तिहास",
+       "history-fieldset-title": "à¤\89à¤\9cळणà¥\8dयà¥\8b à¤\9aाळ",
        "history-show-deleted": "फकत काडून उडयिल्लें",
        "histfirst": "पोरणो",
        "histlast": "नवो ताल्ल",
        "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-suggest": "तुमकां $1 अशें म्हणपाचें आसलें?",
        "search-rewritten": "$1 हाचो निकाल दाखयता.नाजाल्यार $2 हें सोदात.",
        "recentchanges": "हालींचे बदल",
        "recentchanges-legend": "हालींच जाल्ल्या बदलाचो विकल्प",
        "recentchanges-summary": "ह्या विकीचेर हालींच जाल्ल्या बदलांचो माग ह्या भरणांतल्यान दवरात",
+       "recentchanges-noresult": "दिलेल्या काळाचे बदल ह्या निकशाक जुळनांत.‎",
        "recentchanges-feed-description": "ह्या विकीचेर हालींच जाल्ल्या बदलांचो माग ह्या भरणांतल्यान दवरात.",
        "recentchanges-label-newpage": "ह्या संपादनांन नवें पान निर्माण केला.",
        "recentchanges-label-minor": "हें दाक्टे संपादन",
        "recentchanges-label-plusminus": "ह्या पानाचो आकार इतल्या बाइट्सन बदललो",
        "recentchanges-legend-heading": "<strong>कुंजी:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages| नव्या पानांची सुची]] पळयात)",
-       "rcnotefrom": "$2 पासून केल्ले बदल सकयल दिल्यात ($1 मेरेन दाखयल्यात)",
+       "rcnotefrom": "सकयल <strong>$3, $4</strong> सावन {{PLURAL:$5 जालेले बदल दिल्यात}} (<strong>$1</strong> मेरेन {{PLURAL:$5|दाखयलां|दाखयल्यांत}}).",
        "rclistfrom": "$3 $2 साकून नवें बदल दाखयात",
        "rcshowhideminor": "$1 दाकट्यो बदल",
        "rcshowhideminor-show": "दाखयात",
        "rcshowhidebots-show": "दाखयात",
        "rcshowhidebots-hide": "लिपयात",
        "rcshowhideliu": "$1 अधिकृत नोंदीचे वापरपी",
+       "rcshowhideliu-show": "दाखयात",
        "rcshowhideliu-hide": "लिपयात",
        "rcshowhideanons": "$1 निनांवी वापरपी",
        "rcshowhideanons-show": "दाखयात",
        "rcshowhidemine": "$1 म्हजें संपादन आंकडे",
        "rcshowhidemine-show": "दाखयात",
        "rcshowhidemine-hide": "लिपयात",
-       "rclinks": "फाà¤\9fलà¥\8dया $2 à¤¦à¤¿à¤¸à¤¾à¤\82नà¥\80 à¤\9cालà¥\8dलà¥\8b $1 बदल दाखयात",
+       "rclinks": "शà¥\87वà¤\9fà¤\9aà¥\87 $2 à¤¦à¤¿à¤¸à¤¾à¤¨à¥\80à¤\82 à¤\9cालà¥\8dलà¥\87 $1 बदल दाखयात",
        "diff": "फरक",
        "hist": "इति",
        "hide": "लिपयात",
        "filehist-dimensions": "परिमाण",
        "filehist-comment": "शेरो",
        "imagelinks": "फायलिचो वापर",
-       "linkstoimage": "हे फायलीक सकयल दिल्ल्यो पानाच्यो जोडण्यो {{PLURAL:$1|आसात}}.",
-       "nolinkstoimage": "हà¥\87 à¤«à¤¾à¤¯à¤²à¥\80à¤\95 à¤¦à¥\81वà¥\8b à¤\86शिलà¥\8dलà¥\80à¤\82 à¤\86नà¥\80à¤\95 à¤ªà¤¾à¤¨à¤¾à¤\82 à¤¨à¤¾त.",
+       "linkstoimage": "{{PLURAL:$1|हें पान|$1 हीं पानां}} ही फायल {{PLURAL:$1|वापरता|वापरतात}}:",
+       "nolinkstoimage": "हà¥\8dया à¤«à¤¾à¤¯à¤²à¥\80à¤\95 à¤µà¤¾à¤ªà¤°à¤¤à¤¾à¤¤ à¤¤à¤¸à¤²à¥\80à¤\82 à¤ªà¤¾à¤¨à¤¾à¤\82 à¤¨à¤¾à¤\82त.",
        "sharedupload-desc-here": "ही फयल $1 हांगाची आनी ती हे प्रकल्पां खातीर वापरल्यार चलता. (तिच्या $2 ह्या फयलींतलें वर्णनाचे पान) तातूंतलें वर्णन सकयल दिलां.",
        "upload-disallowed-here": "तूं ह्या फायलीचेर अधिलेखीत करूंक शकना",
        "randompage": "खंयचेंय पान",
        "contributions-title": "$1 खातीर वापरप्याचीं योगदानां",
        "mycontris": "योगदान",
        "anoncontribs": "योगदान",
+       "contribsub2": "{{GENDER:$3|$1}} हाच्यो ($2)",
        "uctop": "हालीचें",
        "month": "ह्या म्हयन्या सावन (आनी आदलें):",
        "year": "ह्या वर्सा सावन (आनी आदलें):",
        "sp-contributions-search": "योगदानां सोदात",
        "sp-contributions-username": "आयपी नामो वा वापरप्याचें नांव",
        "sp-contributions-toponly": "फकत सगळ्यांत हालींचे पुनर्नियाळ आशिल्लीं संपादन दाखयात",
+       "sp-contributions-newonly": "फकत तसलेचच बदल दाखय, जांचे वर्वीं पान रचलां",
        "sp-contributions-submit": "सोद",
        "whatlinkshere": "हाका कितें जडता",
        "whatlinkshere-title": " \"$1\" हाका दुवे आशिल्लीं पानां",
        "linkshere": "मुखावेली पानां <strong>$2</strong>: हाका जडतात",
        "nolinkshere": "<strong>$2</strong> हाका खंयच्याच पानाचो दुवो ना",
        "isredirect": "पुनर्निर्देशन पान",
-       "istemplate": "$1 दूसरात-समावेस",
+       "istemplate": "दुरास्थ-समावेस",
        "isimage": "फायलीचो दुवो",
        "whatlinkshere-prev": "{{PLURAL:$1|आदलें|आदलीं $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|फुडलें|फुडलें $1}}",
        "whatlinkshere-links": "← दुवे",
        "whatlinkshere-hideredirs": "$1 पुनर्निर्देशन",
-       "whatlinkshere-hidetrans": "$1 à¤¦à¥\82सà¥\8dरात-समावà¥\87श",
+       "whatlinkshere-hidetrans": "$1 à¤¦à¥\81रासà¥\8dथ-समावà¥\87स",
        "whatlinkshere-hidelinks": "$1 दुवे",
        "whatlinkshere-hideimages": "$1 फायल दुवे",
        "whatlinkshere-filters": "गाळणे",
-       "ipboptions": "2 वरां: 2hours ,1 दीस:1 day,3 दीस:3 days,1 सुमान:1 week,2 सुमनां:2 weeks,1 म्हयनो:1 month,3 म्हयने:3 months,6 म्हयने:6 months,1 वर्स:1 year,अनिश्चीत:infinte",
+       "ipboptions": "2 वरां:2 hours,1 दीस:1 day,3 दीस:3 days,1 सुमान:1 week,2 सुमनां:2 weeks,1 म्हयनो:1 month,3 म्हयने:3 months,6 म्हयने:6 months,1 वर्स:1 year,शेवट ना:infinite",
        "ipblocklist": "आडायल्लें वापरपी",
        "blocklink": "आडावणी",
        "change-blocklink": "विभाग सुदारप",
        "allmessagesdefault": "पूर्वनिर्धारित संदेशाचो मजकूर",
        "thumbnail-more": "व्हड करात",
        "thumbnail_error": "$1ः लघुप्रतिमा करतांनाची चूक",
-       "tooltip-pt-userpage": "तुमचें वापरपाचें पान",
-       "tooltip-pt-mytalk": "तुमचें चर्चेचें पान",
+       "tooltip-pt-userpage": "{{GENDER:|तुमचें वापरप्याचें}} पान",
+       "tooltip-pt-mytalk": "{{GENDER:|तुमचें}} भासाभासाचें पान",
        "tooltip-pt-preferences": "{{GENDER:|तुमची}} पसंती",
        "tooltip-pt-watchlist": "तुमी बदल करपा खातीर देखरेख करतात त्या पानांची वळेरी",
-       "tooltip-pt-mycontris": "तुमच्या योगदानांची वळेरी",
+       "tooltip-pt-mycontris": "{{GENDER:|तुमच्या}} योगदानांची वळेरी",
        "tooltip-pt-login": "सत्रारंभ करप बरें, पूण तशी सक्ती ना.",
        "tooltip-pt-logout": "सत्र शेवट",
        "tooltip-pt-createaccount": "तुमी खातें उगडून सत्रारंभ करचें अशें सुचयतात, पूण तें सक्तीचें ना.",
        "tooltip-t-whatlinkshere": "हांगा दुवे आशिल्ल्या सगळ्या विकी पानांची वळेरी",
        "tooltip-t-recentchangeslinked": "ह्या पानावेल्यान दुवे दिल्ल्या पानांतले हालींचे बदल",
        "tooltip-feed-atom": "ह्या पाना खातीर ऍटम पूर्वण",
-       "tooltip-t-contributions": "ह्या वापरप्याची योगदानाची वळेरी",
+       "tooltip-t-contributions": "{{GENDER:$1|ह्या वापरप्याची}} योगदानाची वळेरी",
        "tooltip-t-emailuser": "{{GENDER:$1|ह्या उपेगकर्त्याक}} इ-मेल धाडात",
        "tooltip-t-upload": "फायली अपलोड करात",
        "tooltip-t-specialpages": "सगळ्या विशेश पानांची वळेरी",
        "tooltip-rollback": "निमाण्या योगदान करप्यान ह्या पानाचेर केल्लें संपादन रोलबॅक  (फाटीं घेयात) एकाच क्लीकान मूळ पदार हाडटा",
        "tooltip-undo": "\"आदलें स्थितीर हाडचें\" ह्या बदलाक परत व्हरुन संपादन स्थितीन झलक रितीन दाखयतात.\nहाचेवरवीं सारांशान आदल्या स्थितीर हाडपाचें कारण बरोवं शकता.",
        "tooltip-summary": "आपरोसाची नोंदणी करात",
-       "simpleantispam-label": "à¤\8fनà¥\8dà¤\9fà¥\80-सà¥\8dपà¥\88म à¤¤à¤ªà¤¾à¤¸à¤ª.\nहà¥\87 à¤­à¤°à¥\80<strong>नà¤\95ाय</strong>!",
+       "simpleantispam-label": "सà¥\8dपमविरà¥\82ध à¤¤à¤ªà¤¾à¤¸à¤£à¥\80.\nहà¥\87à¤\82 à¤­à¤° <strong>नाà¤\95ा</strong>!",
        "pageinfo-toolboxlink": "पानाची म्हायती",
        "pageinfo-contentpage-yes": "हय",
        "previousdiff": "← आदलें संपादन",
index 1fe99ac..9f1f706 100644 (file)
@@ -17,7 +17,7 @@
        "tog-enotifwatchlistpages": "Mhojea sadurvollerintlem pan vo fayl bodol'li zalear mhaka email dhadd",
        "tog-shownumberswatching": "Nodor dovorpi vaporpeanche sonkhya dakhoi",
        "tog-oldsig": "Tujea sod'dheachi soy:",
-       "tog-uselivepreview": "Pan porot ugdinastana zolok dahkoi",
+       "tog-uselivepreview": "Pan porot ughoddnastana zholok dakhoi",
        "tog-watchlisthideown": "Sadurvollerint mhoje bodol lipoi",
        "tog-watchlisthidebots": "Sadurvollerint robotani kel'le bodol lipoi",
        "tog-watchlisthideminor": "Sadurvollerint dhaktem bodol lipoi",
        "listingcontinuesabbrev": "chalu",
        "index-category": "Suchi-potran zodlelim panam",
        "noindex-category": "Suchi-potran zoddunk-naslelim panam",
-       "broken-file-category": "Tuttlolea faylinchea duve aslelim panam‎",
+       "broken-file-category": "Tuttlolea faylinche duve aslelim panam‎",
        "about": "Hea vixoiavoir",
        "article": "Vixoi sombondhi pan",
        "newwindow": "(novea zonelant uktem zata)",
        "youhavenewmessages": "Tumkam $1 ($2) asat.",
        "youhavenewmessagesfromusers": "Tuka {{PLURAL:$3|ek vaporpi|$3 vaporpi}} koddlean $1 {{PLURAL:$4|asa|asat}} ($2).‎",
        "newmessageslinkplural": "{{PLURAL:$1|novo sondex|999=nove sondex}}‎",
-       "newmessagesdifflinkplural": "{{PLURAL:$1|nimanno bodol|999=nimanneo bodol}}",
+       "newmessagesdifflinkplural": "{{PLURAL:$1|nimanno bodol|999=nimanne bodol}}",
        "youhavenewmessagesmulti": "$1 cher tuka noveo sondex asat",
        "editsection": "bodol",
        "editold": "bodol",
        "databaseerror-textcl": "Totv-kox (database) sodtana chuk ghodli",
        "databaseerror-query": "Anurodh: $1",
        "databaseerror-error": "Chuk: $1",
-       "missing-article": "Totv-kox (Database) hantun mellunk zai aslem tem mozkur \"$1\" $2 mellunk-nam.\n\nHorxim, oxem ek pornem frk vo eka panachea itihasacho duvo kadun udoila, tedna zata.\n\nOxem nhoi zalear, tuka softwer-an chuk sampodlam zait.\nUpkar korun eka [[Special:ListUsers/sysop|karbhari]]chea nodrek hadd, Internet Zago Sodpi (URL) hachi nond gheun.",
+       "missing-article": "Totv-kox (Database) hantun mellunk zai aslem tem mozkur \"$1\" $2 mellunk-nam.\n\nHorxim, oxem ek pornem frk vo eka panachea itihasacho duvo kaddun uddoila, ten’na zata.\n\nOxem nhoi zalear, tuka software-ant chuk sampoddlea zait.\nUpkar korun eka [[Special:ListUsers/sysop|karbhari]]chea nodrek hadd, Ontorzalleant Zago Sodpi (URL) hachi nond ghevn.",
        "missingarticle-rev": "(uzollnni#: $1)",
        "missingarticle-diff": "(Frk: $1, $2)",
        "badtitle": "Chukichem nanv",
        "loginerror": "Sotrorombhachi truti",
        "createacct-error": "Khatem rochtanam truti",
        "createaccounterror": "Khatem rochunk zaunk na: $1",
-       "loginsuccesstitle": "Sotrorombh zalem",
+       "loginsuccesstitle": "Sotrarombh zalem",
        "nosuchusershort": "\"$1\" hea nanvan konn vapurpi na.\nNanv boroitana chuk zali gai?",
        "nouserspecified": "Vapurpeachem nanv diunk-uch zai.",
        "login-userblocked": "Hea vapurpeak addaila. Sotrorombh korunk zaina.",
        "emaildisabled": "Hi site mail dhadpak xokona.",
        "accountcreated": "Khatem rochlem.",
        "createaccount-title": "{{SITENAME}} -ak khatem rochlem",
-       "login-abort-generic": "Tujem sotrorombh opexi tharlam - Nixfolit",
+       "login-abort-generic": "Tujem sotrorombh opexi tharlam - Nixfollit",
        "login-migrated-generic": "Tujem khatem stholontrit zalam ani vapurpeachem nanv hea wikicher anink ostitvant na.",
        "loginlanguagelabel": "Bhas: $1",
        "pt-login": "Sotrorombh",
        "passwordreset-domain": "Domain:",
        "passwordreset-email": "Email potto:",
        "passwordreset-emailelement": "Vapurpeachem nanv: \n$1\n\nTatpurtem gupitutor: \n$2",
-       "passwordreset-emailsentemail": "Ho email pot'to tujea kontak zodlelem asa zalear, gupitutor portun tharaipacho email dhadlelem zatelem.",
-       "changeemail": "Email potto bodol vo kad",
+       "passwordreset-emailsentemail": "Ho email pot'to tujea hixobant zoddlolo asa zalear, gupitutor portun tharavpacho email dhaddlelem zatelem.",
+       "changeemail": "Email po’tto bodol vo kadd",
        "changeemail-oldemail": "Sodhyacho email potto:",
        "changeemail-newemail": "Novo email potto:",
        "changeemail-none": "(kai na)",
        "anoneditwarning": "<strong>Chotrai:</strong> Tuven sotrorombh korunk nai. Tu bodol korit zalear tuzo IP pot'to soglleank polleunk zatelem. Tu <strong>[$1 sotrorombh korit]</strong> vo <strong>[$2 kont rochit]</strong> zalear, tuje bodol tuzo vaporpeachem nanvak zoddteleo ani anik-ui faide asat.",
        "missingcommenttext": "Upkar korun tuzo xero boroi.",
        "blockedtitle": "Vapurpeak addaila",
-       "blockedtext": "<strong>Tujem vaporpeachem nanv vo IP pot'to addavpant aila.</strong>\n\nAddavop $1 hannem kelam.\nKaronn dilam tem <em>$2</em>.\n\n* Addavpachi survat: $8\n* Addavpachea somp’pacho vell: $6\n* Addavpak ievjila: $7\n\nTujean $1-ak vo dusrea [[{{MediaWiki:Grouppage-sysop}}|karbhariak]] addavnne bodol bhasabhas korunk sompork korunk zata. Tujean \"{{int:emailuser}}\" sobhavgunn vaprunk zaina kheriz ek void email pot'to tujea [[Special:Preferences|khatem posontint]] nischit kelea xivai ani tuka tem vaporpak addavnk na zalear. Tuzo chalont IP pot'to asa $3, ani addavnnecheo ank #$5 asa. Soglleo voileo bariksanno tum kortai tea vicharant somavex kor.",
+       "blockedtext": "<strong>Tujem vaporpeachem nanv vo IP pot'to addavpant aila.</strong>\n\nAddavop $1 hannem kelam.\nKaronn dilam tem <em>$2</em>.\n\n* Addavpachi survat: $8\n* Addavop sompovpacho vell: $6\n* Addavpak ievjila: $7\n\nTujean $1-ak vo dusrea [[{{MediaWiki:Grouppage-sysop}}|karbhariak]] addavnne bodol bhasabhas korunk sompork korunk zata. Tujean \"{{int:emailuser}}\" sobhavgunn vaprunk zaina kheriz ek void email pot'to tujea [[Special:Preferences|khatem posontint]] nischit kelea xivai ani tuka tem vaporpak addavnk na zalear. Tuzo chalont IP pot'to asa $3, ani addavnnecheo ank #$5 asa. Soglleo voileo bariksanno tum kortai tea vicharant somavex kor.",
        "blockednoreason": "Kainch karonn diunk na",
        "loginreqtitle": "Sotrorombh gorjechem",
        "loginreqlink": "sotrorombh kor",
        "permissionserrors": "Porvangechi chuk",
        "permissionserrorstext-withaction": "$2, hem korpak tuka porvangi na, {{PLURAL:$1|hea karnnak lagon|hea karnnank lagun}}:",
        "recreate-moveddeleted-warn": "<strong>Xittkavnni: Tum ek pan porot rochtai jem fattim kadun udoilelem.<strong>\n\nPanacho sompadon korop sarkem zalear dhean di.\nPan kadoupachem ani halovpachem sotr, sovloti khatir hangasor dilelem asa:",
-       "moveddeleted-notice": "Hem pan kadun udoilelem asa.\nPanachea kadun udounechi, rakhpachi, ani hallovnechi sotr sondorba khatir sokoil dilea.",
+       "moveddeleted-notice": "Hem pan kaddun udoilelem asa.\nPanachem kaddun uddovpachem, rakhpachem, ani halovpachem sotr sondhorba khatir sokoil dila.",
        "content-model-wikitext": "wikimozkur",
        "content-model-text": "Sado mozkur",
        "post-expand-template-inclusion-warning": "<strong>Chotrai:</strong> Sancho zoddpacho akar chod vhodlem asa.\nThodde sache zoddchenant.",
        "page_last": "akhirchem",
        "histlegend": "Frk nivoddni: Jeo uzollneo tuka comparar korunk zai, tenche fudle ''radio'' butao petoi ani ''Enter'' nazalear khalcho butao dab.<br />\nVivron: <strong>({{int:cur}})</strong> = halinchi uzollnie borobor forok, <strong>({{int:last}})</strong> = adli uzollnie borobor forok, <strong>{{int:minoreditletter}}</strong> = dhaktem bodol.",
        "history-fieldset-title": "Uzollnneo chall",
-       "history-show-deleted": "Fokot uzollnni kadun udoilelem",
+       "history-show-deleted": "Fokot uzollnni kadun uddoilolem",
        "histfirst": "sogleavon adhlem",
        "histlast": "sogleavon novem",
        "history-feed-title": "Uzollnniancho itihas",
        "revdel-restore": "Disnnem bodol",
        "pagehist": "Panacho itihas",
        "mergehistory-reason": "Karonn:",
-       "mergelog": "Vilin korpacho sotr",
+       "mergelog": "Vilin korpachem sotr",
        "revertmerge": "Doxim kor",
        "history-title": "\"$1\" hachea uzollnnecho itihas",
        "difference-title": "\"$1\"-chea avrutint ontor",
        "prefs-help-email": "Email potto sokticho na, pun tum gupitutor visroxi zalear gupitutor punorsthapon korunk email pottechi goroz podta.",
        "prefs-help-email-others": "Tujean dusreank tujea vapurpeacho panar vo bhasabhasache panar aslele eke email duve vorvim tuje xim sompork korunk diunk zata.\nDusre tuje xim sompork kortat tednam tuzo email potto tankam kollchenam.",
        "userrights-user-editname": "Ek vapurpeachem nanv ghal:",
-       "group-bot": "Robotam",
+       "group-bot": "Robottam",
        "group-sysop": "Karbhari",
        "group-all": "(soglle)",
        "grouppage-bot": "{{ns:project}}:Robotam",
        "right-move": "Panam haloi",
        "right-writeapi": "Borovpeache API-cho upeog",
        "newuserlogpage": "Vapurpi rochnnechem sotr",
-       "rightslog": "Vaporpeachea hokancho sotr",
+       "rightslog": "Vaporpeachea hokanchem sotr",
        "action-edit": "hem pan sudar",
        "action-createaccount": "hem vaporpeachem khatem roch",
        "nchanges": "$1 {{PLURAL:$1|bodol}}",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|byti}} bodol kel'lea uprant",
        "rc-enhanced-expand": "Bariksann dakhoi",
        "rc-enhanced-hide": "Bariksann lipoi",
-       "rc-old-title": "orombhant rochloli \"$1\" hea nanvan‎.",
+       "rc-old-title": "arombhant rochloli \"$1\" hea nanvan‎",
        "recentchangeslinked": "Sombondit bodol",
        "recentchangeslinked-feed": "Sombondit bodol",
        "recentchangeslinked-toolbox": "Sombondit bodol",
        "longpages": "Lamb panam",
        "protectedpages-filters": "Challnneo:",
        "listusers": "Vaporpeanchi volleri",
-       "usercreated": "$3 hannem $1 disa $2 vaztam rochlelem",
+       "usercreated": "$3 hannem $1 disa $2 vorancher rochlolem",
        "newpages": "Novim panam",
        "move": "Zago bodol",
        "pager-newer-n": "{{PLURAL:$1|novem 1|novim $1}}",
        "specialloguserlabel": "Korpi:",
        "speciallogtitlelabel": "Mokh (mathallo vo {{ns:user}}:vapurpeachem nanv):",
        "log": "Sotram",
-       "all-logs-page": "Soglle bhousache sotram",
-       "alllogstext": "{{SITENAME}} hacheo sogllea uplobdh sotranchi ektthaim dakhovnni.\nTujean tuzo dekhavo ornum ieta ek sotracho prokar vinchun, vaporpeachem nanv (vhodle and dhakte okxora modem forok podta), vo porinnam zalolem pan (hanga-ui vhodle and dhakte okxora modem forok podta).‎",
+       "all-logs-page": "Sogllim bhousachim sotram",
+       "alllogstext": "{{SITENAME}} hacheo sogllea uplobdh sotranchi ektthaim dakhovnni.\nTujean tuzo dekhavo ornum ieta ek sotracho prokar vinchun, vaporpeachem nanv (vhoddlea ani dhakttea okxora modem forok poddtta), vo porinnam zalolem pan (hangai vhoddle and dhaktte okxora modem forok poddtta).",
        "logempty": "Sotran zullpi nog nant.‎",
        "allpages": "Sogllim panam",
        "nextpage": "Fuddlem pan ($1)",
        "allpagesfrom": "Hanga thavn suru zatelea panank dakhoi:",
        "allarticles": "Sogllim panam",
        "allpagessubmit": "Voch",
-       "allpages-hide-redirects": "Punornirdexonam lipoi",
+       "allpages-hide-redirects": "Punornirdexona lipoi",
        "categories": "Vorg",
        "sp-deletedcontributions-contribs": "iogdan",
        "linksearch-ns": "Nanv-tholl:",
        "watch": "Nodor dovor",
        "watchthispage": "Hea panar dixtt dovor",
        "unwatch": "Nodor kadd",
-       "watchlist-details": "Tujea Sadurvollerint {{PLURAL:$1|$1 pan asa|$1 panam asat}} (te-bhair ulovpachim panam asat).",
+       "watchlist-details": "Tujea Sadurvollerint {{PLURAL:$1|$1 pan asa|$1 panam asat}} (tea-bhair ulovpachim panam asat).",
        "wlheader-showupdated": "Tujea fatle bhette san bodol'lean tim panam '''datt''' dakhoileant.",
-       "wlnote": "Sokoil {{PLURAL:$1|ho nimanno bodol|hem nimanneo <strong>$1</strong> bodol}} nimannea {{PLURAL:$2|horan|<strong>$2</strong> horanim}}, $3, $4 porian.‎",
+       "wlnote": "Sokoil {{PLURAL:$1|ho nimanno bodol|hem nimanneo <strong>$1</strong> bodol}} nimannea {{PLURAL:$2|voran|<strong>$2</strong> voramni}}, $3, $4 porian.‎",
        "watchlist-options": "Sadurvollericheo poryay",
        "watching": "Disht dovortanv...",
        "unwatching": "Disht kaddthanv...",
        "linkshere": "Sokoilim panam <strong>$2</strong> ak zoddtat:",
        "nolinkshere": "Khoincheim pan <strong>$2</strong> ak zoddna.",
        "isredirect": "punornirdexon pan",
-       "istemplate": "Durasth-somaves",
+       "istemplate": "durasth-somaves",
        "isimage": "faylicho duvo",
        "whatlinkshere-prev": "{{PLURAL:$1|adlem|adlem $1}}",
        "whatlinkshere-next": "{{PLURAL:$1|fuddlem|fuddlim $1}}",
        "whatlinkshere-links": "← duve",
-       "whatlinkshere-hideredirs": "$1 punornirdexonam",
-       "whatlinkshere-hidetrans": "$1 durasth-somaveso",
+       "whatlinkshere-hideredirs": "$1 punornirdexona",
+       "whatlinkshere-hidetrans": "$1 durasth-somavex",
        "whatlinkshere-hidelinks": "$1 duve",
        "whatlinkshere-hideimages": "$1 faylinche duve",
        "whatlinkshere-filters": "Challnio",
        "contribslink": "yogdan",
        "blocklogpage": "addavnnechem sotr",
        "blocklogentry": "[[$1]] addailelem $2 asun vellacho ont: $3",
-       "reblock-logentry": "addavpachem bosovp bodol’lam [[$1]] hache khatir sompacho vell dilam $2 $3‎",
+       "reblock-logentry": "addavpachem bosovp bodol’lam [[$1]] hache khatir sompovpacho vell dila $2 $3‎",
        "block-log-flags-nocreate": "Khatem rochop opatr kelam",
        "proxyblocker": "Protinidhi-sirvidor addavpi‎",
        "move-page": "$1 haloi",
        "allmessagesdefault": "Default sondex mozkur",
        "thumbnail-more": "Vhodlem kor",
        "thumbnail_error": "Lhan-imaz toiar kortana chuk zali. Karonn: $1",
-       "importlogpage": "Aiatacho sotr",
+       "importlogpage": "Aiatachem sotr",
        "tooltip-pt-userpage": "{{GENDER:|Tujem vaporpeachem}} pan",
        "tooltip-pt-mytalk": "{{GENDER:|Tumchem}} bhasabhasachem pan",
        "tooltip-pt-preferences": "{{GENDER:|Tumcheo}} avddi",
        "tooltip-ca-nstab-special": "Hem ek kherit pan, ani hem bodlunk zaina",
        "tooltip-ca-nstab-project": "Prokolpachem pan polloi",
        "tooltip-ca-nstab-image": "Faylichem pan polloi",
-       "tooltip-ca-nstab-mediawiki": "Iontronacho sondex polloi",
+       "tooltip-ca-nstab-mediawiki": "Iontronnacho sondex polloi",
        "tooltip-ca-nstab-template": "Sancho polloi",
        "tooltip-ca-nstab-category": "Vorgachem pan polloi",
        "tooltip-minoredit": "Haka ek kirkoll sudharop mhunn khunnay",
        "tooltip-rollback": "\"Kovllop\" hea panak nimannea yogdan korpean kello (kelle) bodol eka kollant portota.",
        "tooltip-undo": "\"Rodd' kor\" sudharop portita ani sudharopak Zholok ritin ukodta. Tem saran karon zoddunk dita.",
        "tooltip-summary": "Mottvo sar ghal",
-       "simpleantispam-label": "Spam-virudh topasni.\nHem bhori <strong>nakai</strong>!",
+       "simpleantispam-label": "Spam-virudh topasnni.\nHem bhor <strong>nakai</strong>!",
        "pageinfo-title": "\"$1\" ‎khatir mhaiti",
        "pageinfo-header-basic": "Mull mhaiti‎",
        "pageinfo-header-edits": "Bodolacho itihas",
        "pageinfo-header-properties": "Panache gunndhorm",
        "pageinfo-display-title": "Manddlolem mathallem",
        "pageinfo-default-sort": "Default arin manddunk chavi",
-       "pageinfo-length": "Panachi lambai (bayt-ant)‎",
+       "pageinfo-length": "Panachi lambai (baytt-ant)‎",
        "pageinfo-article-id": "Panacho ank",
        "pageinfo-language": "Panachea mozkurachi bhas",
        "pageinfo-content-model": "Panachea mozkuracho nomuno",
-       "pageinfo-robot-policy": "Robotam koddlean suchien ghalop",
+       "pageinfo-robot-policy": "Robotam koddlean suchent ghalop",
        "pageinfo-robot-index": "Porvangi asa",
        "pageinfo-robot-noindex": "Porvangi nam",
        "pageinfo-watchers": "Panacher dixtt dovortoleancho ankddo",
        "pageinfo-toolboxlink": "Panachi mahiti",
        "pageinfo-contentpage": "Ek mozkurachem pan koxem dhorpant ailam‎",
        "pageinfo-contentpage-yes": "Hoi",
-       "patrol-log-page": "Paro korpeacho sotr",
+       "patrol-log-page": "Paro korpachem sotr",
        "previousdiff": "←  Adlo bodol",
        "nextdiff": "Fuddlem bodol →",
        "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|pan|panam}}",
        "redirect": "Fayl, vaporpi, pan, uzollnni vo sotr ank‎ vorvim punornirdexon kor",
        "redirect-summary": "Hem vixex pan punornirdexit korta eka faylik (faylichem nanv dilear), eke panak (uziollnecho ank vo panacho ank dilear), ek vaporpeachem panak (eke vaporpeache ank dilear), vo ek sotr nond (sotrachem ank dilear). Vapor: [[{{#Special:Redirect}}/file/Dekhik.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]], vo [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Voch‎",
-       "redirect-lookup": "Suchien polloi:",
+       "redirect-lookup": "Suchint polloi:",
        "redirect-value": "Mol:",
-       "redirect-user": "Vaporpeacho ank",
+       "redirect-user": "Vaporpeancho ank",
        "redirect-page": "Panacho ank",
        "redirect-revision": "Panachi uzollnni",
        "redirect-file": "Faylichem nanv",
        "htmlform-title-not-exists": "$1 ostitvant na.",
        "logentry-delete-delete": "$1, hannem {{GENDER:$2|kadun udoile}} pan $3",
        "logentry-delete-restore": "$1 hannem {{GENDER:$2|porot haddlam}} pan $3 ($4)‎",
-       "logentry-delete-revision": "$1 hannem {{PLURAL:$5|uzolliechem}} disnem  $3, hea panar {{GENDER:$2|bodol’la}}: $4‎",
+       "logentry-delete-revision": "$1 hannem {{PLURAL:$5|uzollnnechem}} disnnem $3, hea panar {{GENDER:$2|bodol’la}}: $4‎",
        "revdelete-content-hid": "mozkur lipoila",
        "logentry-move-move": "$1, hannem $3 panak $4 {{GENDER:$2|haloilea}}",
        "logentry-move-move-noredirect": "$1, hannem pan $3 savn $4 {{GENDER:$2|haloilam}} punornirdexon dorinastanam‎",
        "logentry-move-move_redir": "$1 hannem pan $3 savn $4 {{GENDER:$2|haloilolo}} punornirdexonavoir",
-       "logentry-patrol-patrol-auto": "$1-an $3, hea panachem $4, hea uzollniecho paro kelam mhonn apoap {{GENDER:$2|khunnailam}}.",
+       "logentry-patrol-patrol-auto": "$1-an $3, hea panachem $4, hea uzollnnecho paro kelam mhonn apoap {{GENDER:$2|khunnailam}}.",
        "logentry-newusers-create": "Vapurpeacho kont $1 {{GENDER:$2|rochlam}}",
        "logentry-newusers-autocreate": "Vaporpeachem khatem $1 apoap {{GENDER:$2|rochun}} ailem",
        "logentry-upload-upload": "$1-an $3 {{GENDER:$2|upload kela}}",
index 94945ff..d04622a 100644 (file)
        "diff-multi-manyusers": "({{PLURAL:$1|Nije prikazana jedna međuinačica|Nisu prikazane $1 međuinačice|Nije prikazano $1 međuinačica}} više od {{PLURAL:$2|jednog|$2|$2}} suradnika)",
        "difference-missing-revision": "{{PLURAL:$2|Uređivanje|$2 uređivanja}} sljedeće šifre ($1) ne {{PLURAL:$2|postoji|postoje}}.\n\nOvo je obično uzrokovano kada kliknete na zastarjelu poveznicu na stranice koja je obrisana.\nViše informacija možete pronaći u [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} evidenciji brisanja].",
        "searchresults": "Rezultati pretrage",
+       "search-filter-title-prefix": "Pretraži samo stranice koje počinju prefiksom »$1«",
        "searchresults-title": "Rezultati pretrage za \"$1\"",
        "titlematches": "Pronađene stranice prema naslovu",
        "textmatches": "Pronađene stranice prema tekstu članka",
index 8d7fdc1..8bd7bc0 100644 (file)
        "sessionfailure": "ログインのセッションに問題が発生しました。\nセッション乗っ取りを防ぐため、操作を取り消しました。\nフォームを再送信してください。",
        "changecontentmodel": "ページのコンテンツ・モデルの変更",
        "changecontentmodel-legend": "コンテンツモデルを変更",
-       "changecontentmodel-title-label": "ページ名",
+       "changecontentmodel-title-label": "ページ名:",
        "changecontentmodel-current-label": "現在のコンテンツモデル",
-       "changecontentmodel-model-label": "新しい コンテンツ モデル",
+       "changecontentmodel-model-label": "新しい コンテンツ モデル:",
        "changecontentmodel-reason-label": "理由:",
        "changecontentmodel-submit": "変更",
        "changecontentmodel-success-title": "コンテンツ・モデルは変更されました",
index e63cd39..410e3ab 100644 (file)
        "undo-norev": "Измената не можеше да биде вратена бидејќи не постои или била избришана.",
        "undo-nochange": "Се чини дека измената (уредувањето) е веќе вратена.",
        "undo-summary": "Откажано уредувањето $1 на уредникот [[Special:Contribs/$2|$2]] ([[User talk:$2|разговор]])",
+       "undo-summary-anon": "Отповикај ја преработката $1 на [[Special:Contributions/$2|$2]]",
        "undo-summary-username-hidden": "Поништи ја преработката $1 на скриен корисник",
        "cantcreateaccount-text": "Создавањето на корисничка сметка од оваа IP-адреса (<strong>$1</strong>) е блокирано од страна на [[User:$3|$3]].\n\nОбразложението дадено од страна на $3 е <em>$2</em>",
        "cantcreateaccount-range-text": "Создавањето на сметки од IP-адреси во опсегот <strong>$1</strong> каде спаѓа вашата IP-адреса (<strong>$4</strong>) е блокирано од корисникот [[User:$3|$3]].\n\n$3 ја наведе следнава причина: <em>$2</em>",
        "cantrollback": "Уредувањето не може да се отповика.\nПоследниот уредник е воедно и единствениот автор на страницата.",
        "alreadyrolled": "Не може да се отповика последното уредување на страницата „[[:$1]]“ извршено од  [[User:$2|$2]] ([[User talk:$2|разговор]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nнекој друг веќе ја изменил или отповикал страницата.\n\nПоследното уредување го изврши [[User:$3|$3]] ([[User talk:$3|разговор]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Коментарот на уредувањето беше: <em>$1</em>.",
-       "revertpage": "Отстрането уредувањето на [[Special:Contributions/$2|$2]] ([[User talk:$2|разговор]]), вратено на последната верзија на [[User:$1|$1]]",
+       "revertpage": "Отповикани уредувањата на [[Special:Contributions/$2|$2]] ([[User talk:$2|разговор]]), враќајќи на последната преработка на [[User:$1|$1]]",
+       "revertpage-anon": "Отповикани уредувања на [[Special:Contributions/$2|$2]], враќајќи на последната преработка на [[User:$1|$1]]",
        "revertpage-nouser": "Вратени уредувања од скриен корисник на последната преработка на {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Откажани уредувањата на {{GENDER:$3|$1}};\nвратено на последната верзија на {{GENDER:$4|$2}}.",
        "sessionfailure-title": "Седницата не успеа",
index 25d7bf1..04fec53 100644 (file)
                        "Railfail536",
                        "Vlad5250",
                        "CiaPan",
-                       "BadDog"
+                       "BadDog",
+                       "Rail"
                ]
        },
        "tog-underline": "Podkreślenie linków:",
index 478a52e..a33608f 100644 (file)
        "tog-useeditwarning": "Used as label for the checkbox in [[Special:Preferences#mw-prefsection-editing|Special:Preferences]].",
        "tog-prefershttps": "Toggle option used in [[Special:Preferences]] that indicates if the user wants to use a secure connection when logged in",
        "tog-showrollbackconfirmation": "Toggle option used in [[Special:Preferences]] to enable/disable rollback confirmation prompt. Should be visible only to users with rollback rights.",
+       "tog-requireemail": "Toggle option used in [[Special:Preferences]].  Should be only visible to users who have confirmed their email address.\n\nSee also: {{msg-mw|prefs-help-requireemail}}",
        "underline-always": "Used in [[Special:Preferences#mw-prefsection-rendering|Preferences]].\n\nThis option means \"always underline links\", there are also options {{msg-mw|Underline-never}} and {{msg-mw|Underline-default}}.\n\n{{Gender}}\n{{Identical|Always}}",
        "underline-never": "Used in [[Special:Preferences#mw-prefsection-rendering|Preferences]].\n\nThis option means \"never underline links\", there are also options {{msg-mw|Underline-always}} and {{msg-mw|Underline-default}}.\n\n{{Gender}}\n{{Identical|Never}}",
        "underline-default": "Used in [[Special:Preferences#mw-prefsection-rendering|Preferences]].\n\nThis option means \"underline links as in your user skin or your browser\", there are also options {{msg-mw|Underline-never}} and {{msg-mw|Underline-always}}.\n\n{{Gender}}\n{{Identical|Browser default}}",
        "prefs-help-email": "Shown as explanation text on [[Special:Preferences]] > {{int:prefs-personal}} > {{int:email}}.\n\nSee also:\n* {{msg-mw|prefs-help-email-required|help}}\n* {{msg-mw|prefs-help-email-others|help}}\n* {{msg-mw|prefs-changeemail|link title}}\n* {{msg-mw|prefs-setemail|link title}}",
        "prefs-help-email-others": "This text is shown on account creation, below the description of the e-mail address field (which is optional).\n\nSee also:\n* {{msg-mw|prefs-help-email-required|help}}\n* {{msg-mw|prefs-help-email|help}}\n* {{msg-mw|prefs-changeemail|link title}}\n* {{msg-mw|prefs-setemail|link title}}",
        "prefs-help-email-required": "Shown as explanation text on [[Special:Preferences]] > {{int:prefs-personal}} > {{int:email}}.\n\nSee also:\n* {{msg-mw|prefs-help-email|help}}\n* {{msg-mw|prefs-help-email-others|help}}\n* {{msg-mw|prefs-changeemail|link title}}\n* {{msg-mw|prefs-setemail|link title}}",
+       "prefs-help-requireemail": "Shown as explanation text on [[Special:Preferences]] > {{int:prefs-personal}} > {{int:email}}.\n\nSee also: {{msg-mw|tog-requireemail}}",
        "prefs-info": "Header for the box giving basic information on the user account, displayed on the 'user profile' tab of the [[Special:Preferences|user preferences]] special page.\n{{Identical|Basic information}}",
        "prefs-i18n": "Field set legend for user preferences regarding the interface language",
        "prefs-signature": "{{Identical|Signature}}",
        "ipblocklist-legend": "Used as legend of the form in [[Special:BlockList]].\n\nSee also:\n* {{msg-mw|Ipblocklist-legend}}\n* {{msg-mw|Ipblocklist-submit}}",
        "blocklist-userblocks": "Used as the label for the multi-select checkbox in the form on [[Special:BlockList]].\n{{Related|Blocklist-blocks}}",
        "blocklist-tempblocks": "Used as the label for the multi-select checkbox in the form on [[Special:BlockList]].\n{{Related|Blocklist-blocks}}",
+       "blocklist-indefblocks": "Used as the label for the multi-select checkbox in the form on [[Special:BlockList]].\n{{Related|Blocklist-blocks}}",
        "blocklist-addressblocks": "Used as the label for the multi-select checkbox in the form on [[Special:BlockList]].\n{{Related|Blocklist-blocks}}",
        "blocklist-type": "Used as label for dropdown box in [[Special:BlockList]].",
        "blocklist-type-opt-all": "Used as option for dropdown box in [[Special:BlockList]]. This is the default option and indicates that \"all\" blocks will be listed\n{{Identical|All}}",
index 5fe33ce..dcc686b 100644 (file)
        "undo-norev": "Redigeringen kan inte göras ogjord eftersom den inte finns eller har raderats.",
        "undo-nochange": "Det verkar som att redigeringen redan har blivit ogjord.",
        "undo-summary": "Gör version $1 av [[Special:Contributions/$2|$2]] ([[User talk:$2|diskussion]]) ogjord",
+       "undo-summary-anon": "Ångra sidversionen $1 av [[Special:Contributions/$2|$2]]",
        "undo-summary-username-hidden": "Gör version $1 av en dold användare ogjord",
        "cantcreateaccount-text": "[[User:$3|$3]] har blockerat den här IP-adressen ('''$1''') från att registrera konton.\n\nAnledningen till blockeringen var \"$2\".",
        "cantcreateaccount-range-text": "IP-adresserna i intervallet <strong>$1</strong>, som inkluderar din IP-adress (<strong>$4</strong>), har blockerats från att skapa konton av [[User:$3|$3]].\n\nAnledningen enligt $3 var <em>$2</em>",
        "alreadyrolled": "Det gick inte att rulla tillbaka den senaste redigeringen av [[User:$2|$2]] ([[User talk:$2|diskussion]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]) på sidan [[:$1|$1]]. Någon annan har redan rullat tillbaka eller redigerat sidan.\n\nSidan ändrades senast av [[User:$3|$3]] ([[User talk:$3|diskussion]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]).",
        "editcomment": "Redigeringskommentaren var: <em>$1</em>.",
        "revertpage": "Återställde redigeringar av  [[Special:Contributions/$2|$2]] ([[User talk:$2|användardiskussion]]) till senaste versionen av [[User:$1|$1]]",
+       "revertpage-anon": "Ångrade redigeringar av [[Special:Contributions/$2|$2]] till senaste sidversionen av [[User:$1|$1]]",
        "revertpage-nouser": "Återställde redigeringar av en dold användare till den senaste versionen av {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Återställde ändringar av {{GENDER:$3|$1}};\nändrade tillbaka till senaste versionen av {{GENDER:$4|$2}}.",
        "sessionfailure-title": "Sessionsfel",
index cd35ab2..8446ebd 100644 (file)
        "morenotlisted": "Ńy je to kůmplytno lista",
        "mypage": "Zajta",
        "mytalk": "Dyskusyjŏ",
-       "anontalk": "Godka tygo IP",
+       "anontalk": "Dyskusyjŏ",
        "navigation": "Nawigacyjŏ",
        "and": "&#32;i",
        "faq": "FAQ",
        "filereadonlyerror": "Ńy idźe pomjyńać plika \"$1\" abo repozytorjum \"$2\" terozki je zawarte.\n\nAdministrator kery zawarł wćepał kůmyntorz: \"$3\".",
        "invalidtitle-knownnamespace": "Felerne mjano \"$3\" w przestrzeńy \"$2\".",
        "invalidtitle-unknownnamespace": "Felerne mjano ze ńyznomům nůmerům raumu mjan $1: \"$2\"",
-       "exception-nologin": "Ńy jest żeś zalogůwany",
+       "exception-nologin": "Niy je żeś wlogowany(ŏ)",
        "exception-nologin-text": "Prosza [[Special:Userlogin|zaloguj śe]] coby mjeć mogebność przejśćo do tyj zajty abo akcyji.",
        "virus-badscanner": "Felerno konfiguracyjo – ńyznany skaner antywirusowy ''$1''",
        "virus-scanfailed": "skanowańy ńyudone (feler $1)",
        "changepassword-success": "Twoje hasło zostoło půmyślńy půmjyńone!",
        "botpasswords": "Hasła bota",
        "resetpass_forbidden": "Ńy idźe sam půmjyńyć hasłůw.",
-       "resetpass-no-info": "Muśisz być zalogowany, coby uzyskoć bezpostrzedńi dostymp do tyj zajty.",
+       "resetpass-no-info": "Żeby mieć bezpostrzedni dostymp do tyj strōny, trzeba sie zalogować.",
        "resetpass-submit-loggedin": "Zmjyń hasło",
        "resetpass-submit-cancel": "Uodćepej",
        "resetpass-wrong-oldpass": "Felerne tymczasowe abo aktualne hasło.\nMożliwe co właśńy zmjyńiłżeś swoje hasło abo poprosiłżeś uo nowe tymczasowe hasło.",
        "showpreview": "Pokŏż podglōnd",
        "showdiff": "Pokŏż zmiany",
        "anoneditwarning": "<strong>Pozōr:</strong> Niy je żeś wlogowany(ŏ). Jak zrobisz jakeś zmiany, to Twoja adresa IP bydzie publicznie widać. Jeźli <strong>[$1 sie wlogujesz]</strong> abo <strong>[$2 stworzisz kōnto]</strong>, to Twoje zmiany bydōm przipisane do kōnta społym ze inkszymi profitami.",
-       "anonpreviewwarning": "Ńy jeżeś zalogowany. Twój IP ausdruk uostańy spamjyntany, eli ty bydźesz sprowjać zajte.",
+       "anonpreviewwarning": "<em>Niy je żeś wlogowany(ŏ). Spamiyntanie zmian zapisze twoja adresa IP we historyji edycyji tyj strōny.</em>",
        "missingsummary": "'''Pozůr:''' Ńy wprowadźůł żeś uopisu pomjyńań. Kej go ńy chcesz wprowadzać, naćiś knefel Spamjyntej jeszcze roz.",
        "missingcommenttext": "Wkludź kōmyntŏrz niżyj.",
        "missingcommentheader": "'''Dej pozůr:''' Treść nagłůwka je blank - uzupełńij go! Jeli tego ńy zrobisz, Twůj kůmyntorz bydźe naszkryflony bez nagłůwka.",
        "upload": "Zaladuj zbiōr",
        "uploadbtn": "Prziślij zbiōr",
        "reuploaddesc": "Nazod do formulařa uod wćepywańo.",
-       "uploadnologin": "Ńy jest žeś zalogůwany",
+       "uploadnologin": "Niy je żeś wlogowany(ŏ)",
        "uploadnologintext": "Muśyš śe [[Special:UserLogin|zalůgować]] ńim wćepńeš pliki.",
        "upload_directory_missing": "Katalog lo wćepywanych plikůw ($1) ńy istńeje a serwer WWW ńy poradźi go utwořić.",
        "upload_directory_read_only": "Serwer ńy može škryflać do katalůgu ($1) kery je přeznačůny na wćepywane pliki.",
        "linksearch-text": "Idźe użyć symbola wjeloznacznygo „*”. Lů bajszpila „*.wikipedia.org” spowoduje sznupańy za wszyjstkimi linkůma kere prowadzům ku důmyńy „wikipedia.org” a jeij poddůmyn.<br />\nUobsůgiwane protokoły: $1",
        "linksearch-line": "$1 link na zajće $2",
        "linksearch-error": "Symbola wjeloznacznygo idźe użyć yno na anfangu mjana hosta.",
-       "listusersfrom": "Pokaž užytkowńikůw začynojůnc uod:",
+       "listusersfrom": "Pokŏż używŏczōw ôd:",
        "listusers-submit": "Uobejrzij",
        "listusers-noresult": "Ńy znejdźůno žodnygo užytkowńika.",
        "activeusers": "Lista aktywnych używŏczōw",
        "watchlistfor2": "{{GENDER:$1|Używŏcza|Używŏczki}} $1 $2",
        "nowatchlist": "Ńy ma žodnych pozycyji na liśće zajtůw, na kere dowoš pozůr.",
        "watchlistanontext": "$1 coby uobejřeć abo sprowjać elymynty listy zajtůw, na kere dowoš pozůr",
-       "watchnologin": "Ńy jest žeś zalůgowany",
+       "watchnologin": "Niy je żeś wlogowany(ŏ)",
        "addedwatchtext": "Zajta \"[[:$1]]\" zostoua dodano do Twojij [[Special:Watchlist|listy artiklůw, na kere dowoš pozůr]].\nNa tyi liśće bydźeš mjou rejer přišuych sprowjyń tyi zajty i jeji zajty godki, a mjano zajty bydźeš mjou škryflane '''tustym''' na [[Special:RecentChanges|liśće půmjyńanych na ůostatku]], cobyś mjou wygoda w jei pomjyńańa filować.",
        "removedwatchtext": "Artikel \"[[:$1]]\" zostou wyćepńjynty s [[Special:Watchlist|Twojij pozorlisty]].",
        "watch": "Ôbserwuj",
        "movepage-moved": "'''\"$1\" przećiśńjynto ku \"$2\"'''",
        "articleexists": "Artikel ze takym mjanym już je, abo mjano je złe.\nWybjer inksze mjano.",
        "cantmove-titleprotected": "Ńy możesz przećepnůńć zajty, beztuż co jeij nowe mjano je ńydozwolůne skuli zabezpjeczyńo przed utworzyńym",
-       "movetalk": "Przećiś godke, jak możno.",
+       "movetalk": "Przeniyś zwiōnzanõ ze strōnōm dyskusyjõ",
        "move-subpages": "Přećepńij podzajty",
        "move-talk-subpages": "Jeli je to możliwe przekludź wszyjstke zajty godki podzajtůw",
        "movepage-page-exists": "Zajta $1 już istńeje a ńy idźe jeij autůmatyczńy nadszkryflać.",
index 16310eb..bda0a4f 100644 (file)
        "grouppage-suppress": "{{ns:project}}:Назирләр",
        "right-read": "Битләрне карау",
        "right-edit": "Битләрне үзгәртү",
-       "right-createpage": "биÑ\82лÓ\99Ñ\80 Ñ\8fÑ\81аÑ\83 (бÓ\99Ñ\85Ó\99Ñ\81 Ð±Ñ\83лмаганнаÑ\80Ñ\8bн)",
-       "right-createtalk": "бÓ\99Ñ\85Ó\99Ñ\81 Ð±Ð¸Ñ\82ен Ñ\8fÑ\81аÑ\83",
-       "right-createaccount": "яңа кулланучы хисап язмасын ясау",
+       "right-createpage": "Ð\91иÑ\82лÓ\99Ñ\80не Ñ\82өзү (бÓ\99Ñ\85Ó\99Ñ\81 Ð±Ð¸Ñ\82лÓ\99Ñ\80е Ð±Ñ\83лмаган)",
+       "right-createtalk": "Ð\91Ó\99Ñ\85Ó\99Ñ\81 Ð±Ð¸Ñ\82лÓ\99Ñ\80ен Ñ\82өзү",
+       "right-createaccount": "Яңа кулланучы хисап язмасын төзү",
        "right-minoredit": "\"кече төзәтмә\" тамгасын кую",
        "right-move": "Битләрне күчерү",
        "right-move-subpages": "Битләрне асбитләр белән бергә күчерү",
index 208449b..c2cd05b 100644 (file)
        "editcomment": "編輯摘要為:<em>$1</em>。",
        "revertpage": "已還原[[Special:Contributions/$2|$2]]([[User talk:$2|討論]])的編輯至最後由[[User:$1|$1]]所修訂的版本",
        "revertpage-nouser": "已還原隱藏使用者的編輯為最後 {{GENDER:$1|[[User:$1|$1]]}} 修訂的版本",
-       "rollback-success": "已還原 {{GENDER:$3|$1}} 所做的編輯;\n變更回由 {{GENDER:$4|$2}} 修訂的最後一個版本。",
+       "rollback-success": "已還原{{GENDER:$3|$1}}所做的編輯;變更回由{{GENDER:$4|$2}}修訂的最後一個版本。",
        "sessionfailure-title": "連線階段失敗",
        "sessionfailure": "您的登入連線階段似乎有問題,為了預防連線階段受到劫持攻擊,此動作已經被取消。請重新提交表單。",
        "changecontentmodel": "變更頁面的內容模型",
index cad6122..5602e39 100644 (file)
@@ -133,7 +133,7 @@ class TitleCleanup extends TableCleanup {
         * @param Title $title
         */
        protected function moveInconsistentPage( $row, Title $title ) {
-               if ( $title->exists( Title::GAID_FOR_UPDATE )
+               if ( $title->exists( Title::READ_LATEST )
                        || $title->getInterwiki()
                        || !$title->canExist()
                ) {
index 979e68a..e3c6c02 100644 (file)
@@ -1,6 +1,6 @@
 -- Blobs table for external storage
 
-CREATE TABLE /*$wgDBprefix*/blobs (
+CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/blobs (
        blob_id integer UNSIGNED NOT NULL AUTO_INCREMENT,
        blob_text longblob,
        PRIMARY KEY  (blob_id)
index 060f327..37625cf 100644 (file)
@@ -232,7 +232,7 @@ class CheckStorage {
                                }
                                foreach ( $externalConcatBlobs as $cluster => $xBlobIds ) {
                                        $blobIds = array_keys( $xBlobIds );
-                                       $extDb =& $this->dbStore->getSlave( $cluster );
+                                       $extDb =& $this->dbStore->getReplica( $cluster );
                                        $blobsTable = $this->dbStore->getTable( $extDb );
                                        $res = $extDb->select( $blobsTable,
                                                [ 'blob_id' ],
@@ -433,7 +433,7 @@ class CheckStorage {
 
                foreach ( $externalConcatBlobs as $cluster => $oldIds ) {
                        $blobIds = array_keys( $oldIds );
-                       $extDb =& $this->dbStore->getSlave( $cluster );
+                       $extDb =& $this->dbStore->getReplica( $cluster );
                        $blobsTable = $this->dbStore->getTable( $extDb );
                        $headerLength = strlen( self::CONCAT_HEADER );
                        $res = $extDb->select( $blobsTable,
index 98f1c24..2f8941f 100644 (file)
@@ -110,11 +110,10 @@ The new option is NOT validated.' );
                                        $ret[$option][$userValue] = ( $ret[$option][$userValue] ?? 0 ) + 1;
                                }
                        } else {
-
                                foreach ( $defaultOptions as $name => $defaultValue ) {
                                        $userValue = $user->getOption( $name );
                                        if ( $userValue != $defaultValue ) {
-                                               $ret[$option][$userValue] = ( $ret[$option][$userValue] ?? 0 ) + 1;
+                                               $ret[$name][$userValue] = ( $ret[$name][$userValue] ?? 0 ) + 1;
                                        }
                                }
                        }
index 18faeea..82ccb9a 100644 (file)
@@ -768,12 +768,12 @@ class TitleTest extends MediaWikiTestCase {
                $this->assertEquals(
                        false,
                        $title->exists(),
-                       'exists() should rely on link cache unless GAID_FOR_UPDATE is used'
+                       'exists() should rely on link cache unless READ_LATEST is used'
                );
                $this->assertEquals(
                        true,
-                       $title->exists( Title::GAID_FOR_UPDATE ),
-                       'exists() should re-query database when GAID_FOR_UPDATE is used'
+                       $title->exists( Title::READ_LATEST ),
+                       'exists() should re-query database when READ_LATEST is used'
                );
        }
 
index c68954c..d2bbc1f 100644 (file)
@@ -67,7 +67,7 @@ class ApiDeleteTest extends ApiTestCase {
                $jobs->loadParamsAndArgs( null, [ 'quiet' => true ], null );
                $jobs->execute();
 
-               $this->assertFalse( Title::newFromText( $name )->exists( Title::GAID_FOR_UPDATE ) );
+               $this->assertFalse( Title::newFromText( $name )->exists( Title::READ_LATEST ) );
        }
 
        public function testDeleteNonexistent() {
index a4ca8a1..5dcea65 100644 (file)
@@ -22,8 +22,7 @@ class ApiRevisionDeleteTest extends ApiTestCase {
                // Make a few edits for us to play with
                for ( $i = 1; $i <= 5; $i++ ) {
                        self::editPage( self::$page, MWCryptRand::generateHex( 10 ), 'summary' );
-                       $this->revs[] = Title::newFromText( self::$page )
-                               ->getLatestRevID( Title::GAID_FOR_UPDATE );
+                       $this->revs[] = Title::newFromText( self::$page )->getLatestRevID( Title::READ_LATEST );
                }
        }
 
index cd0867d..b2f525d 100644 (file)
@@ -259,14 +259,14 @@ class SessionManagerTest extends MediaWikiTestCase {
                try {
                        $manager->getSessionForRequest( $request );
                        $this->fail( 'Expcected exception not thrown' );
-               } catch ( \OverflowException $ex ) {
+               } catch ( SessionOverflowException $ex ) {
                        $this->assertStringStartsWith(
                                'Multiple sessions for this request tied for top priority: ',
                                $ex->getMessage()
                        );
-                       $this->assertCount( 2, $ex->sessionInfos );
-                       $this->assertContains( $request->info1, $ex->sessionInfos );
-                       $this->assertContains( $request->info2, $ex->sessionInfos );
+                       $this->assertCount( 2, $ex->getSessionInfos() );
+                       $this->assertContains( $request->info1, $ex->getSessionInfos() );
+                       $this->assertContains( $request->info2, $ex->getSessionInfos() );
                }
                $this->assertFalse( $request->unpersist1 );
                $this->assertFalse( $request->unpersist2 );
index 58f83de..a95d43c 100644 (file)
@@ -22,7 +22,7 @@ class QueryAllSpecialPagesTest extends MediaWikiTestCase {
 
        /** List query pages that can not be tested automatically */
        protected $manualTest = [
-               LinkSearchPage::class
+               SpecialLinkSearch::class
        ];
 
        /**
index 4ecb813..08225a6 100644 (file)
@@ -2,15 +2,15 @@
 
 /**
  * @group Database
- * @covers MIMEsearchPage
+ * @covers SpecialMIMESearch
  */
 class SpecialMIMESearchTest extends MediaWikiTestCase {
 
-       /** @var MIMEsearchPage */
+       /** @var SpecialMIMESearch */
        private $page;
 
        function setUp() {
-               $this->page = new MIMEsearchPage;
+               $this->page = new SpecialMIMESearch;
                $context = new RequestContext();
                $context->setTitle( Title::makeTitle( NS_SPECIAL, 'MIMESearch' ) );
                $context->setRequest( new FauxRequest() );
diff --git a/tests/phpunit/includes/specials/SpecialShortPagesTest.php b/tests/phpunit/includes/specials/SpecialShortPagesTest.php
new file mode 100644 (file)
index 0000000..8891d0d
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Test class for SpecialShortPages class
+ *
+ * @since 1.30
+ *
+ * @license GPL-2.0-or-later
+ */
+class SpecialShortPagesTest extends MediaWikiTestCase {
+
+       /**
+        * @dataProvider provideGetQueryInfoRespectsContentNs
+        * @covers SpecialShortPages::getQueryInfo()
+        */
+       public function testGetQueryInfoRespectsContentNS( $contentNS, $blacklistNS, $expectedNS ) {
+               $this->setMwGlobals( [
+                       'wgShortPagesNamespaceBlacklist' => $blacklistNS,
+                       'wgContentNamespaces' => $contentNS
+               ] );
+               $this->setTemporaryHook( 'ShortPagesQuery', function () {
+                       // empty hook handler
+               } );
+
+               $page = new SpecialShortPages();
+               $queryInfo = $page->getQueryInfo();
+
+               $this->assertArrayHasKey( 'conds', $queryInfo );
+               $this->assertArrayHasKey( 'page_namespace', $queryInfo[ 'conds' ] );
+               $this->assertEquals( $expectedNS, $queryInfo[ 'conds' ][ 'page_namespace' ] );
+       }
+
+       public function provideGetQueryInfoRespectsContentNs() {
+               return [
+                       [ [ NS_MAIN, NS_FILE ], [], [ NS_MAIN, NS_FILE ] ],
+                       [ [ NS_MAIN, NS_TALK ], [ NS_FILE ], [ NS_MAIN, NS_TALK ] ],
+                       [ [ NS_MAIN, NS_FILE ], [ NS_FILE ], [ NS_MAIN ] ],
+                       // NS_MAIN namespace is always forced
+                       [ [], [ NS_FILE ], [ NS_MAIN ] ]
+               ];
+       }
+
+}
diff --git a/tests/phpunit/includes/specials/SpecialShortpagesTest.php b/tests/phpunit/includes/specials/SpecialShortpagesTest.php
deleted file mode 100644 (file)
index 236c5c4..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-
-/**
- * Test class for SpecialShortpages class
- *
- * @since 1.30
- *
- * @license GPL-2.0-or-later
- */
-class SpecialShortpagesTest extends MediaWikiTestCase {
-
-       /**
-        * @dataProvider provideGetQueryInfoRespectsContentNs
-        * @covers ShortPagesPage::getQueryInfo()
-        */
-       public function testGetQueryInfoRespectsContentNS( $contentNS, $blacklistNS, $expectedNS ) {
-               $this->setMwGlobals( [
-                       'wgShortPagesNamespaceBlacklist' => $blacklistNS,
-                       'wgContentNamespaces' => $contentNS
-               ] );
-               $this->setTemporaryHook( 'ShortPagesQuery', function () {
-                       // empty hook handler
-               } );
-
-               $page = new ShortPagesPage();
-               $queryInfo = $page->getQueryInfo();
-
-               $this->assertArrayHasKey( 'conds', $queryInfo );
-               $this->assertArrayHasKey( 'page_namespace', $queryInfo[ 'conds' ] );
-               $this->assertEquals( $expectedNS, $queryInfo[ 'conds' ][ 'page_namespace' ] );
-       }
-
-       public function provideGetQueryInfoRespectsContentNs() {
-               return [
-                       [ [ NS_MAIN, NS_FILE ], [], [ NS_MAIN, NS_FILE ] ],
-                       [ [ NS_MAIN, NS_TALK ], [ NS_FILE ], [ NS_MAIN, NS_TALK ] ],
-                       [ [ NS_MAIN, NS_FILE ], [ NS_FILE ], [ NS_MAIN ] ],
-                       // NS_MAIN namespace is always forced
-                       [ [], [ NS_FILE ], [ NS_MAIN ] ]
-               ];
-       }
-
-}
diff --git a/tests/phpunit/includes/specials/SpecialUncategorizedCategoriesTest.php b/tests/phpunit/includes/specials/SpecialUncategorizedCategoriesTest.php
new file mode 100644 (file)
index 0000000..daccd27
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Tests for Special:UncategorizedCategories
+ */
+class SpecialUncategorizedCategoriesTest extends MediaWikiTestCase {
+       /**
+        * @dataProvider provideTestGetQueryInfoData
+        * @covers SpecialUncategorizedCategories::getQueryInfo
+        */
+       public function testGetQueryInfo( $msgContent, $expected ) {
+               $msg = new RawMessage( $msgContent );
+               $mockContext = $this->getMockBuilder( RequestContext::class )->getMock();
+               $mockContext->method( 'msg' )->willReturn( $msg );
+               $special = new SpecialUncategorizedCategories();
+               $special->setContext( $mockContext );
+               $this->assertEquals( [
+                       'tables' => [
+                               0 => 'page',
+                               1 => 'categorylinks',
+                       ],
+                       'fields' => [
+                               'namespace' => 'page_namespace',
+                               'title' => 'page_title',
+                               'value' => 'page_title',
+                       ],
+                       'conds' => [
+                               0 => 'cl_from IS NULL',
+                               'page_namespace' => 14,
+                               'page_is_redirect' => 0,
+                       ] + $expected,
+                       'join_conds' => [
+                               'categorylinks' => [
+                                       0 => 'LEFT JOIN',
+                                       1 => 'cl_from = page_id',
+                               ],
+                       ],
+               ], $special->getQueryInfo() );
+       }
+
+       public function provideTestGetQueryInfoData() {
+               return [
+                       [
+                               "* Stubs\n* Test\n* *\n* * test123",
+                               [ 1 => "page_title not in ( 'Stubs','Test','*','*_test123' )" ]
+                       ],
+                       [
+                               "Stubs\n* Test\n* *\n* * test123",
+                               [ 1 => "page_title not in ( 'Test','*','*_test123' )" ]
+                       ],
+                       [
+                               "* StubsTest\n* *\n* * test123",
+                               [ 1 => "page_title not in ( 'StubsTest','*','*_test123' )" ]
+                       ],
+                       [ "", [] ],
+                       [ "\n\n\n", [] ],
+                       [ "\n", [] ],
+                       [ "Test\n*Test2", [ 1 => "page_title not in ( 'Test2' )" ] ],
+                       [ "Test", [] ],
+                       [ "*Test\nTest2", [ 1 => "page_title not in ( 'Test' )" ] ],
+                       [ "Test\nTest2", [] ],
+               ];
+       }
+}
diff --git a/tests/phpunit/includes/specials/UncategorizedCategoriesPageTest.php b/tests/phpunit/includes/specials/UncategorizedCategoriesPageTest.php
deleted file mode 100644 (file)
index 80bd365..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
- * Tests for Special:Uncategorizedcategories
- */
-class UncategorizedCategoriesPageTest extends MediaWikiTestCase {
-       /**
-        * @dataProvider provideTestGetQueryInfoData
-        * @covers UncategorizedCategoriesPage::getQueryInfo
-        */
-       public function testGetQueryInfo( $msgContent, $expected ) {
-               $msg = new RawMessage( $msgContent );
-               $mockContext = $this->getMockBuilder( RequestContext::class )->getMock();
-               $mockContext->method( 'msg' )->willReturn( $msg );
-               $special = new UncategorizedCategoriesPage();
-               $special->setContext( $mockContext );
-               $this->assertEquals( [
-                       'tables' => [
-                               0 => 'page',
-                               1 => 'categorylinks',
-                       ],
-                       'fields' => [
-                               'namespace' => 'page_namespace',
-                               'title' => 'page_title',
-                               'value' => 'page_title',
-                       ],
-                       'conds' => [
-                               0 => 'cl_from IS NULL',
-                               'page_namespace' => 14,
-                               'page_is_redirect' => 0,
-                       ] + $expected,
-                       'join_conds' => [
-                               'categorylinks' => [
-                                       0 => 'LEFT JOIN',
-                                       1 => 'cl_from = page_id',
-                               ],
-                       ],
-               ], $special->getQueryInfo() );
-       }
-
-       public function provideTestGetQueryInfoData() {
-               return [
-                       [
-                               "* Stubs\n* Test\n* *\n* * test123",
-                               [ 1 => "page_title not in ( 'Stubs','Test','*','*_test123' )" ]
-                       ],
-                       [
-                               "Stubs\n* Test\n* *\n* * test123",
-                               [ 1 => "page_title not in ( 'Test','*','*_test123' )" ]
-                       ],
-                       [
-                               "* StubsTest\n* *\n* * test123",
-                               [ 1 => "page_title not in ( 'StubsTest','*','*_test123' )" ]
-                       ],
-                       [ "", [] ],
-                       [ "\n\n\n", [] ],
-                       [ "\n", [] ],
-                       [ "Test\n*Test2", [ 1 => "page_title not in ( 'Test2' )" ] ],
-                       [ "Test", [] ],
-                       [ "*Test\nTest2", [ 1 => "page_title not in ( 'Test' )" ] ],
-                       [ "Test\nTest2", [] ],
-               ];
-       }
-}